home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / elm2.3 / part16 < prev    next >
Text File  |  1990-06-07  |  50KB  |  1,814 lines

  1. Subject:  v22i075:  ELM mail syste, release 2.3, Part16/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: ff7bd791 91ac6a0c 5c8879f1 c04da152
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 75
  8. Archive-name: elm2.3/part16
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 16 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file src/hdrconfg.c continued
  15. #
  16. CurArch=16
  17. if test ! -r s2_seq_.tmp
  18. then echo "Please unpack part 1 first!"
  19.      exit 1; fi
  20. ( read Scheck
  21.   if test "$Scheck" != $CurArch
  22.   then echo "Please unpack part $Scheck next!"
  23.        exit 1;
  24.   else exit 0; fi
  25. ) < s2_seq_.tmp || exit 1
  26. echo "x - Continuing file src/hdrconfg.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> src/hdrconfg.c
  28. X            (void) build_address(strip_commas(cc), expanded_cc);
  29. X            put_cc();
  30. X            break;
  31. X
  32. X        case 'r' :  PutLine0(INPUT_LINE, 0, "Reply-To: "); CleartoEOLN();
  33. X                if(optionally_enter(reply_to,
  34. X                  INPUT_LINE, 10, FALSE, FALSE) == -1)
  35. X              return(0);
  36. X            put_replyto();
  37. X            break;
  38. X
  39. X        case 'a' :  PutLine0(INPUT_LINE, 0, "Action: "); CleartoEOLN();
  40. X                if (optionally_enter(action,
  41. X                  INPUT_LINE, 8, FALSE, FALSE) == -1)
  42. X              return(0);
  43. X            put_action();
  44. X            break;
  45. X
  46. X        case 'p' :  PutLine0(INPUT_LINE, 0, "Priority: "); CleartoEOLN();
  47. X                if (optionally_enter(priority,
  48. X                  INPUT_LINE, 10, FALSE, FALSE)==-1)
  49. X              return(0);
  50. X            put_priority();
  51. X            break;
  52. X
  53. X        case 'e' :  enter_date(expires);
  54. X            put_expires();
  55. X            break;
  56. X
  57. X        case 'u' :  PutLine0(EXTRA_PROMPT_LINE, 0, "User defined header: ");
  58. X            CleartoEOLN();
  59. X                if (optionally_enter(user_defined_header,
  60. X                 INPUT_LINE, 0, FALSE, FALSE)==-1)
  61. X              return(0);
  62. X            check_user_header(user_defined_header);
  63. X            put_userdefined();
  64. X            ClearLine(EXTRA_PROMPT_LINE);
  65. X            break;
  66. X
  67. X        case 'i' : if (strlen(in_reply_to) > 0) {
  68. X             PutLine0(INPUT_LINE, 0, "In-Reply-To: "); CleartoEOLN();
  69. X                     if (optionally_enter(in_reply_to,
  70. X                 INPUT_LINE, 13, FALSE, FALSE) == -1)
  71. X               return(0);
  72. X             put_inreplyto();
  73. X             break;        
  74. X               }
  75. X
  76. X#ifdef ALLOW_SUBSHELL
  77. X        case '!':  if (subshell())
  78. X             display_headers();
  79. X               continue;
  80. X#endif
  81. X
  82. X        default  : Centerline(ERROR_LINE, "No such header!");
  83. X               displayed_error = YES;
  84. X      }
  85. X    }
  86. X}
  87. X
  88. Xdisplay_headers()
  89. X{
  90. X    char buffer[SLEN];
  91. X
  92. X    ClearScreen();
  93. X
  94. X    Centerline(0,"Message Header Edit Screen");
  95. X
  96. X    put_to();
  97. X    put_cc();
  98. X    put_bcc();
  99. X    put_subject();
  100. X    put_replyto();
  101. X    put_action();
  102. X    put_expires();
  103. X    put_priority();
  104. X    if (in_reply_to[0])
  105. X      put_inreplyto();
  106. X    if (user_defined_header[0])
  107. X      put_userdefined();
  108. X
  109. X    strcpy(buffer, "Choose first letter of header, u)ser defined header, ");
  110. X#ifdef ALLOW_SUBSHELL
  111. X    strcat(buffer, "!)shell, ");
  112. X#endif
  113. X    strcat(buffer, "or <return>.");
  114. X    Centerline(INSTRUCT_LINE, buffer);
  115. X}
  116. X
  117. Xstatic
  118. Xput_header(hline, hcount, field, value)
  119. Xint     hline, hcount;
  120. Xchar    *field, *value;
  121. X{
  122. X    char    *p;
  123. X    int     x, y;
  124. X
  125. X    MoveCursor(hline, 0);
  126. X
  127. X    if (field) {
  128. X      for (p = field; *p; ++p)
  129. X        Writechar(*p);
  130. X      Writechar(':');
  131. X      Writechar(' ');
  132. X    }
  133. X
  134. X    GetXYLocation(&x, &y);
  135. X
  136. X    for (p = value; *p; ++p) {
  137. X      if (x >= (hline + hcount))
  138. X          break;
  139. X      /* neat hack alert -- danger will robinson */
  140. X      if ((x + 1) == (hline + hcount)
  141. X       && (y + 4) == COLUMNS && strlen(p) > 4)
  142. X        p = " ...";
  143. X      Writechar(*p);
  144. X      ++y;
  145. X      if (*p < 0x20 || *p >= 0x7F || y >= COLUMNS)
  146. X        GetXYLocation(&x, &y);
  147. X    }
  148. X
  149. X    if (x < (hline + hcount)) {
  150. X      CleartoEOLN();
  151. X
  152. X      while (++x < (hline + hcount)) {
  153. X        MoveCursor(x, 0);
  154. X        CleartoEOLN();
  155. X      }
  156. X    }
  157. X}
  158. X
  159. Xenter_date(datebuf)
  160. Xchar *datebuf;
  161. X{
  162. X    /** Enter the number of days this message is valid for, then
  163. X        display at (x,y) the actual date of expiration.  This 
  164. X        routine relies heavily on the routine 'days_ahead()' in
  165. X        the file date.c
  166. X    **/
  167. X
  168. X    int days;
  169. X    char numdaysbuf[SLEN];
  170. X
  171. X    static char prompt[] =
  172. X      "How many days in the future should this message expire? ";
  173. X
  174. X    PutLine0(INPUT_LINE,0, prompt);
  175. X    CleartoEOLN();
  176. X    *datebuf = *numdaysbuf = '\0';
  177. X
  178. X    optionally_enter(numdaysbuf, INPUT_LINE, strlen(prompt), FALSE, FALSE);
  179. X    sscanf(numdaysbuf, "%d", &days);
  180. X    if (days < 1)
  181. X      Centerline(ERROR_LINE, "That doesn't make sense!");
  182. X    else if (days > 56)
  183. X      Centerline(ERROR_LINE, 
  184. X         "Expiration date must be within eight weeks of today.");
  185. X    else {
  186. X      days_ahead(days, datebuf);
  187. X    }
  188. X}
  189. X
  190. Xcheck_user_header(header)
  191. Xchar *header;
  192. X{
  193. X    /** check the header format...if bad print error and erase! **/
  194. X
  195. X    register int i = -1;
  196. X
  197. X    if (strlen(header) == 0)
  198. X       return;
  199. X
  200. X    if (whitespace(header[0])) {
  201. X      error ("You can't have leading white space in a header!");
  202. X      header[0] = '\0';
  203. X      ClearLine(USER_DEFINED_HDR_LINE);
  204. X      return;
  205. X    }
  206. X
  207. X    if (header[0] == ':') {
  208. X      error ("You can't have a colon as the first character!");
  209. X      header[0] = '\0';
  210. X      ClearLine(USER_DEFINED_HDR_LINE);
  211. X      return;
  212. X    }
  213. X
  214. X    while (header[++i] != ':') {
  215. X      if (header[i] == '\0') {
  216. X        Centerline(ERROR_LINE, "You need to have a colon ending the field name!");
  217. X        header[0] = '\0';
  218. X        ClearLine(USER_DEFINED_HDR_LINE);
  219. X        return;
  220. X      }
  221. X      else if (whitespace(header[i])) {
  222. X        Centerline(ERROR_LINE, "You can't have white space imbedded in the header name!");
  223. X        header[0] = '\0';
  224. X        ClearLine(USER_DEFINED_HDR_LINE);
  225. X        return;
  226. X      }
  227. X    }
  228. X    
  229. X    return;
  230. X}
  231. SHAR_EOF
  232. echo "File src/hdrconfg.c is complete"
  233. chmod 0444 src/hdrconfg.c || echo "restore of src/hdrconfg.c fails"
  234. echo "x - extracting src/help.c (Text)"
  235. sed 's/^X//' << 'SHAR_EOF' > src/help.c &&
  236. X
  237. Xstatic char rcsid[] = "@(#)$Id: help.c,v 4.1 90/04/28 22:43:11 syd Exp $";
  238. X
  239. X/*******************************************************************************
  240. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  241. X *
  242. X *             Copyright (c) 1986, 1987 Dave Taylor
  243. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  244. X *******************************************************************************
  245. X * Bug reports, patches, comments, suggestions should be sent to:
  246. X *
  247. X *    Syd Weinstein, Elm Coordinator
  248. X *    elm@DSI.COM            dsinc!elm
  249. X *
  250. X *******************************************************************************
  251. X * $Log:    help.c,v $
  252. X * Revision 4.1  90/04/28  22:43:11  syd
  253. X * checkin of Elm 2.3 as of Release PL0
  254. X * 
  255. X *
  256. X ******************************************************************************/
  257. X
  258. X/*** help routine for ELM program 
  259. X
  260. X***/
  261. X
  262. X#include <ctype.h>
  263. X#include "headers.h"
  264. X
  265. Xhelp(pager_help)
  266. Xint pager_help;
  267. X{
  268. X    /** Process the request for help [section] from the user.
  269. X        If pager_help is TRUE, then act a little differently from
  270. X        if pager_help is FALSE (index screen)
  271. X     **/
  272. X
  273. X    char ch;        /* character buffer for input */
  274. X    char *s;        /* string pointer...          */
  275. X    int prompt_line, info_line;
  276. X    static char help_message[] =
  277. X   "Press the key you want help for, '?' for a key list, or '.' to exit help";
  278. X    static char help_prompt[] = "Help for key: ";
  279. X
  280. X    MoveCursor(LINES-4,0);
  281. X    CleartoEOS();
  282. X
  283. X    if(pager_help) {
  284. X      put_border();
  285. X      Centerline(LINES, help_message);
  286. X      prompt_line = LINES-3;
  287. X    } else {
  288. X      Centerline(LINES-4, "ELM Help System");
  289. X      Centerline(LINES-3, help_message);
  290. X      prompt_line = LINES-2;
  291. X    }
  292. X    info_line = prompt_line + 1;
  293. X
  294. X    PutLine0(prompt_line, 0, help_prompt);
  295. X
  296. X    do {
  297. X      MoveCursor(prompt_line, strlen(help_prompt));
  298. X      ch = ReadCh();
  299. X      
  300. X      if (ch == '.') return(0);    /* zero means footer rewrite only */
  301. X
  302. X      s = "Unknown command.  Use '?' for a list of commands.";
  303. X
  304. X      switch (ch) {
  305. X
  306. X        case '?': display_helpfile(pager_help? PAGER_HELP : MAIN_HELP);
  307. X              return(1);
  308. X
  309. X        case '$': if(!pager_help) s =
  310. X"$ = Force resynchronization of the current folder. This will purge deleted mail.";
  311. X              break;
  312. X
  313. X        case '!': s = 
  314. X     "! = Escape to the Unix shell of your choice, or just to enter commands.";
  315. X                  break;
  316. X
  317. X        case '@': if(!pager_help) s = 
  318. X       "@ = Debug - display a summary of the messages on the header page.";
  319. X              break;
  320. X
  321. X        case '|': s = 
  322. X   "| = Pipe the current message or tagged messages to the command specified.";
  323. X              break;
  324. X
  325. X        case '#': if(!pager_help) s = 
  326. X        "# = Debug - display all information known about current message.";
  327. X              break;
  328. X
  329. X        case '%': s = 
  330. X     "% = Debug - display the computed return address of the current message.";
  331. X              break;
  332. X
  333. X        case '*': if(!pager_help)
  334. X               s = "* = Go to the last message in the current folder.";
  335. X              break;
  336. X
  337. X        case '-': if(!pager_help) s = 
  338. X"- = Go to the previous page of messages.  This is the same as the LEFT arrow.";
  339. X              break;
  340. X
  341. X        case '=': if(!pager_help) s = 
  342. X            "'=' = Go to the first message in the current folder.";
  343. X              break;
  344. X
  345. X        case ' ': if(pager_help) s =
  346. X  "<space> = Display next screen of current message (or first screen of next).";
  347. X              else s = "<space> = Display the current message.";
  348. X              break;
  349. X
  350. X        case '+': if(!pager_help)
  351. X                s = 
  352. X  "+ = Go to the next page of messages.  This is the same as the RIGHT arrow.";
  353. X              break;
  354. X
  355. X        case '/': if(!pager_help)
  356. X            s = "/ = Search for specified pattern in folder.";
  357. X              break;
  358. X
  359. X        case '<': s = 
  360. X           "< = Scan current message for calendar entries (if enabled).";
  361. X              break;
  362. X
  363. X        case '>': s = 
  364. X           "> = Save current message or tagged messages to specified file.";
  365. X              break;
  366. X
  367. X        case '^': if(!pager_help) s = 
  368. X           "^ = Toggle the Delete/Undelete status of the current message.";
  369. X              break;
  370. X
  371. X        case 'a': if(!pager_help) s = 
  372. X       "a = Enter the alias sub-menu section.  Create and display aliases.";
  373. X              break;
  374. X
  375. X        case 'b': s = 
  376. X      "b = Bounce (remail) a message to someone as if you have never seen it.";
  377. X              break;
  378. X
  379. X        case 'C': s = 
  380. X               "C = Copy current message or tagged messages to specified file.";
  381. X              break;
  382. X
  383. X        case 'c': if(!pager_help) s = 
  384. X     "c = Change folders, leaving the current folder as if 'quitting'.";
  385. X              break;
  386. X
  387. X        case 'd': s = "d = Mark the current message for future deletion.";
  388. X              break;
  389. X
  390. X        case ctrl('D') : if(!pager_help) s =
  391. X          "^D = Mark for deletion all messages with the specified pattern.";
  392. X              break;
  393. X
  394. X        case 'e': if(!pager_help) s = 
  395. X     "e = Invoke the editor on the entire folder, resynchronizing when done.";
  396. X              break;
  397. X
  398. X        case 'f': s = 
  399. X    "f = Forward the current message to someone, return address is yours.";
  400. X              break;
  401. X
  402. X        case 'g': s = 
  403. X   "g = Group reply not only to the sender, but to everyone who received msg.";
  404. X              break;
  405. X
  406. X        case 'h': s = 
  407. X         "h = Display message with all Headers (ignore weedout list).";
  408. X                  break;
  409. X
  410. X        case 'i': if(pager_help) s = "i = Return to the index.";
  411. X              break;
  412. X
  413. X        case 'J': s = "J = Go to the next message.";
  414. X              break;
  415. X
  416. X        case 'j': s = 
  417. X  "j = Go to the next undeleted message.  This is the same as the DOWN arrow.";
  418. X              break;
  419. X
  420. X        case 'K': s = "K = Go to the previous message.";
  421. X              break;
  422. X
  423. X        case 'k': s = 
  424. X"k = Go to the previous undeleted message.  This is the same as the UP arrow.";
  425. X              break;
  426. X
  427. X        case 'l': if(!pager_help) s =
  428. X               "l = Limit displayed messages based on the specified criteria.";
  429. X              break;
  430. X
  431. X        case 'm': s = 
  432. X         "m = Create and send mail to the specified person or persons.";
  433. X              break;
  434. X
  435. X        case 'n': if(pager_help)
  436. X            s = "n = Display the next message.";
  437. X              else
  438. X            s = 
  439. X       "n = Display the current message, then move current to next messge.";
  440. X              break;
  441. X
  442. X        case 'o': if(!pager_help) s = "o = Go to the options submenu.";
  443. X                  break;
  444. X
  445. X        case 'p': s = 
  446. X              "p = Print the current message or the tagged messages.";
  447. X                  break;
  448. X
  449. X        case 'q': if(pager_help) s = 
  450. X            "q = Quit the pager and return to the index.";
  451. X              else s =
  452. X            "q = Quit the mailer, asking about deletion, saving, etc.";
  453. X              break;
  454. X
  455. X        case 'r': s = 
  456. X"r = Reply to the message.  This only sends to the originator of the message.";
  457. X                  break;
  458. X
  459. X        case 's': s = 
  460. X               "s = Save current message or tagged messages to specified file.";
  461. X              break;
  462. X
  463. X        case 't': s = 
  464. X               "t = Tag a message for further operations (or untag if tagged).";
  465. X              break;
  466. X
  467. X        case ctrl('T') : if(!pager_help) s =
  468. X                "^T = Tag all messages with the specified pattern.";
  469. X              break;
  470. X
  471. X        case 'u': s =
  472. X              "u = Undelete - remove the deletion mark on the message.";
  473. X              break;
  474. X
  475. X        case 'x': s = "x = Exit the mail system quickly.";
  476. X              break;
  477. X
  478. X        case 'Q': if(!pager_help) s = 
  479. X        "Q = Quick quit the mailer, save read, leave unread, delete deleted.";
  480. X              break;
  481. X
  482. X        case '\n':
  483. X        case '\r': if(pager_help)
  484. X             s =
  485. X  "<return> = Display current message, or (builtin pager only) scroll forward.";
  486. X               else
  487. X             s = "<return> = Display the current message.";
  488. X               break;
  489. X
  490. X        case ctrl('L'): if(!pager_help) s = "^L = Rewrite the screen.";    
  491. X               break;
  492. X
  493. X            case ctrl('?'):                        /* DEL */
  494. X        case ctrl('Q'): if(!pager_help) s = "Exit the mail system quickly.";
  495. X               break;
  496. X
  497. X        default : if (isdigit(ch) && !pager_help) 
  498. X                s = "<number> = Make specified number the current message.";
  499. X      }
  500. X
  501. X      ClearLine(info_line);
  502. X      Centerline(info_line, s);
  503. X
  504. X    } while (ch != '.');
  505. X    
  506. X    /** we'll never actually get here, but that's okay... **/
  507. X
  508. X    return(0);
  509. X}
  510. X
  511. Xdisplay_helpfile(section)
  512. Xint section;
  513. X{
  514. X    /*** Help me!  Read file 'helpfile.<section>' and echo to screen ***/
  515. X
  516. X    char buffer[SLEN];
  517. X
  518. X    sprintf(buffer, "%s/%s.%d", helphome, helpfile, section);
  519. X    return(display_file(buffer));
  520. X}
  521. X
  522. Xdisplay_file(file)
  523. Xchar *file;
  524. X{
  525. X    /*** Display file to screen ***/
  526. X
  527. X    FILE *fileptr;
  528. X    int  lines=0;
  529. X    char buffer[SLEN];
  530. X
  531. X    if ((fileptr = fopen(file,"r")) == NULL) {
  532. X      dprint(1, (debugfile,
  533. X         "Error: Couldn't open file %s (help)\n", file));
  534. X      error1("Couldn't open file %s.",file);
  535. X      return(FALSE);
  536. X    }
  537. X    
  538. X    ClearScreen();
  539. X
  540. X    while (fgets(buffer, SLEN, fileptr) != NULL) {
  541. X      if (lines > LINES-3) {
  542. X        PutLine0(LINES,0,"Press <space> to continue, 'q' to return.");
  543. X        if(ReadCh() == 'q') {
  544. X          clear_error();
  545. X          fclose(fileptr);
  546. X          return(TRUE);
  547. X        }
  548. X        lines = 0;
  549. X        ClearScreen();
  550. X        Write_to_screen("%s\r", 1, buffer);
  551. X      }
  552. X      else 
  553. X        Write_to_screen("%s\r", 1, buffer);
  554. X
  555. X      lines += strlen(buffer)/COLUMNS + 1;
  556. X    }
  557. X
  558. X        PutLine0(LINES,0,"Press any key to return.");
  559. X
  560. X    (void) ReadCh();
  561. X    clear_error();
  562. X
  563. X    fclose(fileptr);
  564. X    return(TRUE);
  565. X}
  566. SHAR_EOF
  567. chmod 0444 src/help.c || echo "restore of src/help.c fails"
  568. echo "x - extracting src/in_utils.c (Text)"
  569. sed 's/^X//' << 'SHAR_EOF' > src/in_utils.c &&
  570. X
  571. Xstatic char rcsid[] = "@(#)$Id: in_utils.c,v 4.1 90/04/28 22:43:13 syd Exp $";
  572. X
  573. X/*******************************************************************************
  574. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  575. X *
  576. X *             Copyright (c) 1986, 1987 Dave Taylor
  577. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  578. X *******************************************************************************
  579. X * Bug reports, patches, comments, suggestions should be sent to:
  580. X *
  581. X *    Syd Weinstein, Elm Coordinator
  582. X *    elm@DSI.COM            dsinc!elm
  583. X *
  584. X *******************************************************************************
  585. X * $Log:    in_utils.c,v $
  586. X * Revision 4.1  90/04/28  22:43:13  syd
  587. X * checkin of Elm 2.3 as of Release PL0
  588. X * 
  589. X *
  590. X ******************************************************************************/
  591. X
  592. X/** Mindless I/O routines for ELM 
  593. X    
  594. X**/
  595. X
  596. X#include "headers.h"
  597. X#include <errno.h>
  598. X#include <ctype.h>
  599. X
  600. X#ifdef BSD
  601. X#  undef tolower
  602. X#endif
  603. X
  604. Xextern int errno;        /* system error number */
  605. X
  606. Xunsigned alarm();
  607. X
  608. X#define isstopchar(c)        (c == ' ' || c == '\t' || c == '/')
  609. X#define isslash(c)        (c == '/')
  610. X#define erase_a_char()        { Writechar(BACKSPACE); Writechar(' '); \
  611. X                      Writechar(BACKSPACE); fflush(stdout); }
  612. X
  613. Xint
  614. Xwant_to(question, dflt)
  615. Xchar *question, dflt;
  616. X{
  617. X    /** Ask 'question' on LINES-2 left enough to just leave room for an
  618. X        answer, returning the answer in lower case.
  619. X        Echo answer as full "Yes" or "No".  'dflt' is the 
  620. X        default answer if <return> is pressed. (Note: 'dflt' is also what 
  621. X        will be returned if <return> is pressed!)
  622. X    **/
  623. X    register int ch, cols;
  624. X
  625. X    cols = COLUMNS - (strlen(question) + 5 );    /* 5 for "Yes." + 1 */
  626. X
  627. X    MoveCursor(LINES-3, cols);
  628. X    CleartoEOLN();
  629. X    PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
  630. X    fflush(stdout);
  631. X    fflush(stdin);
  632. X
  633. X    ch = ReadCh();
  634. X    ch = tolower(ch);
  635. X
  636. X    while (!( ch == 'y' || ch == 'n' || ch == '\n' || ch == '\r')) {
  637. X      ch = ReadCh();
  638. X      ch = tolower(ch);
  639. X    }
  640. X    if(ch == '\n' || ch == '\r')
  641. X      ch = dflt;
  642. X
  643. X    if(ch == 'y')
  644. X      Write_to_screen("Yes.", 0);
  645. X    else
  646. X      Write_to_screen("No.", 0);
  647. X
  648. X    return(ch);
  649. X}
  650. X
  651. Xint
  652. Xread_number(ch)
  653. Xchar ch;
  654. X{
  655. X    /** Read a number, where 'ch' is the leading digit! **/
  656. X    
  657. X    char buff[NLEN];
  658. X    int  num;
  659. X
  660. X    buff[0] = ch;
  661. X    buff[1] = '\0';
  662. X
  663. X    PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
  664. X    if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE, FALSE) == -1)
  665. X      return(current);
  666. X
  667. X    sscanf(buff,"%d", &num);
  668. X    return(num);
  669. X}
  670. X
  671. Xint
  672. Xoptionally_enter(string, x, y, append_current, passwd)
  673. Xchar *string;
  674. Xint  x,y, append_current, passwd;
  675. X{
  676. X    /** This will display the string on the screen and allow the user to
  677. X        either accept it (by pressing RETURN) or alter it according to
  678. X        what the user types.   The various flags are:
  679. X             string    is the buffer to use (with optional initial value)
  680. X          x,y       is the location we're at on the screen (-1,-1 means
  681. X               that we can't use this info and need to find out
  682. X               the current location)
  683. X         append_current  means that we have an initial string and that
  684. X               the cursor should be placed at the END of the line,
  685. X               not the beginning (the default).
  686. X         passwd       accept non-printing characters and do not echo
  687. X               entered characters.
  688. X          
  689. X        If we hit an interrupt or EOF we'll return non-zero.
  690. X    **/
  691. X
  692. X    int ch;
  693. X    register int ch_count = 0, iindex = 0, escaped = OFF;
  694. X
  695. X    clearerr(stdin);
  696. X
  697. X    if(!passwd) {
  698. X      if(!(x >=0 && y >= 0))
  699. X        GetXYLocation(&x, &y);
  700. X      PutLine1(x, y, "%s", string);    
  701. X    }
  702. X
  703. X    CleartoEOLN();
  704. X
  705. X    if (! append_current) {
  706. X      MoveCursor(x,y);
  707. X    }
  708. X    else
  709. X      iindex = strlen(string);
  710. X
  711. X    if (cursor_control)
  712. X      transmit_functions(OFF);
  713. X
  714. X    /** now we have the screen as we want it and the cursor in the 
  715. X        right place, we can loop around on the input and return the
  716. X        string as soon as the user presses <RETURN>
  717. X    **/
  718. X
  719. X    do {
  720. X      ch = getchar();
  721. X
  722. X      if (ch == ctrl('D') || ch == EOF) {        /* we've hit EOF */
  723. X        if (cursor_control)
  724. X          transmit_functions(ON);
  725. X        return(1);
  726. X      }
  727. X
  728. X      if (ch_count++ == 0) {
  729. X        if (ch == '\n' || ch == '\r') {
  730. X          if (cursor_control)
  731. X            transmit_functions(ON);
  732. X          return(0);
  733. X        }
  734. X        else if (! append_current) {
  735. X          CleartoEOLN();
  736. X          iindex = (append_current? strlen(string) : 0);
  737. X        }
  738. X      }
  739. X
  740. X      /* the following is converted from a case statement to
  741. X         allow the variable characters (backspace, kill_line
  742. X         and break) to be processed.  Case statements in
  743. X         C require constants as labels, so it failed ...
  744. X      */
  745. X
  746. X      if (ch == backspace &&
  747. X        (!escaped || (!isprint(ch) && !passwd))) {
  748. X        /* This is tricky. Here we are dealing with all situations
  749. X         * under which a backspace (really whatever erase char is
  750. X         * set to, not necessarily \b) erases the previous character.
  751. X         * It will erase unless escaped, because if it's escaped
  752. X         * it is taken literally. There is one exception to that --
  753. X         * if backspace would be rejected (we don't accept non-printing
  754. X         * characters in non-passwd mode), we accept it here as an
  755. X         * erasing character, for it if got rejected there would
  756. X         * be no way of erasing a preceding backslash. */
  757. X        escaped = OFF;
  758. X        if (iindex > 0) {
  759. X          if(!passwd)
  760. X        Writechar(BACKSPACE);
  761. X            iindex--;
  762. X        }
  763. X        if(!passwd) {
  764. X          Writechar(' ');
  765. X          Writechar(BACKSPACE);
  766. X          fflush(stdout);
  767. X        }
  768. X      }
  769. X      else if (ch == EOF || ch == '\n' || ch == '\r') {
  770. X        escaped = OFF;
  771. X        string[iindex] = '\0';
  772. X        if (cursor_control)
  773. X          transmit_functions(ON);
  774. X        return(0);
  775. X      }
  776. X      else if (!passwd && ch == ctrl('W')) {    /* back up a word! */
  777. X        escaped = OFF;
  778. X        if (iindex == 0)
  779. X          continue;        /* no point staying here.. */
  780. X        iindex--;
  781. X        if (isslash(string[iindex])) {
  782. X          erase_a_char();
  783. X        }
  784. X        else {
  785. X          while (iindex >= 0 && isspace(string[iindex])) {
  786. X            iindex--;
  787. X            erase_a_char();
  788. X          }
  789. X
  790. X          while (iindex >= 0 && ! isstopchar(string[iindex])) {
  791. X            iindex--;
  792. X            erase_a_char();
  793. X          }
  794. X          iindex++;    /* and make sure we point at the first AVAILABLE slot */
  795. X        }
  796. X      }
  797. X      else if (!passwd && ch == ctrl('R')) {
  798. X        escaped = OFF;
  799. X        string[iindex] = '\0';
  800. X        PutLine1(x,y, "%s", string);    
  801. X        CleartoEOLN();
  802. X      }
  803. X      else if (!escaped && ch == kill_line) {
  804. X        /* needed to test if escaped since kill_line character could
  805. X         * be a desired valid printing character */
  806. X        escaped = OFF;
  807. X        if(!passwd) {
  808. X          MoveCursor(x,y);
  809. X          CleartoEOLN();
  810. X        }
  811. X        iindex = 0;
  812. X      }
  813. X      else if (ch == '\0') {
  814. X        escaped = OFF;
  815. X        if (cursor_control)
  816. X          transmit_functions(ON);
  817. X        fflush(stdin);     /* remove extraneous chars, if any */
  818. X        string[0] = '\0'; /* clean up string, and... */
  819. X        return(-1);
  820. X      }
  821. X      else if (!passwd && !isprint(ch)) {
  822. X        /* non-printing character - warn with bell*/
  823. X        /* don't turn off escaping backslash since current character
  824. X         * doesn't "use it up".
  825. X         */
  826. X        Writechar('\007');
  827. X      }
  828. X      else {  /* default case */
  829. X          if(escaped && (ch == backspace || ch == kill_line)) {
  830. X        /* if last character was a backslash,
  831. X         * and if this character is escapable
  832. X         * simply write this character over it even if
  833. X         * this character is a backslash.
  834. X         */
  835. X        if(!passwd)
  836. X          Writechar(BACKSPACE);
  837. X        iindex--;
  838. X        string[iindex++] = ch;
  839. X        if(!passwd)
  840. X          Writechar(ch);
  841. X            escaped = OFF;
  842. X          } else {
  843. X        string[iindex++] = ch;
  844. X        if(!passwd)
  845. X          Writechar(ch);
  846. X        escaped = ( ch == '\\' ? ON : OFF);
  847. X          }
  848. X      }
  849. X    } while (iindex < SLEN);
  850. X
  851. X    string[iindex] = '\0';
  852. X
  853. X    if (cursor_control)
  854. X      transmit_functions(ON);
  855. X
  856. X    return(0);
  857. X}
  858. X
  859. Xint
  860. Xpattern_enter(string, alt_string, x, y, alternate_prompt)
  861. Xchar *string, *alt_string, *alternate_prompt;
  862. Xint  x,y;
  863. X{
  864. X    /** This function is functionally similar to the routine
  865. X        optionally-enter, but if the first character pressed
  866. X        is a '/' character, then the alternate prompt and string
  867. X        are used rather than the normal one.  This routine 
  868. X        returns 1 if alternate was used, 0 if not
  869. X    **/
  870. X
  871. X    int ch;
  872. X    register iindex = 0, escaped = OFF;
  873. X
  874. X    PutLine1(x, y, "%s", string);    
  875. X    CleartoEOLN();
  876. X    MoveCursor(x,y);
  877. X
  878. X    if (cursor_control)
  879. X      transmit_functions(OFF);
  880. X
  881. X    ch = getchar();
  882. X
  883. X    if (ch == '\n' || ch == '\r') {
  884. X      if (cursor_control)
  885. X        transmit_functions(ON);
  886. X      return(0);    /* we're done.  No change needed */
  887. X    }
  888. X    
  889. X    if (ch == '/') {
  890. X      PutLine1(x, 0, "%s", alternate_prompt);
  891. X      CleartoEOLN();
  892. X      (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
  893. X         FALSE, FALSE);
  894. X      return(1);
  895. X    }
  896. X
  897. X    CleartoEOLN();
  898. X
  899. X    iindex = 0;
  900. X
  901. X    if (ch == kill_line) {
  902. X      MoveCursor(x,y);
  903. X          CleartoEOLN();
  904. X      iindex = 0;
  905. X    }
  906. X    else if (ch != backspace) {
  907. X      if(ch == '\\') escaped = ON;
  908. X      Writechar(ch);
  909. X      string[iindex++] = ch;
  910. X    }
  911. X    else if (iindex > 0) {
  912. X      iindex--;
  913. X      erase_a_char();
  914. X    }
  915. X    else {
  916. X      Writechar(' ');
  917. X      Writechar(BACKSPACE);
  918. X    }
  919. X
  920. X    do {
  921. X      fflush(stdout);
  922. X      ch = getchar();
  923. X
  924. X      /* the following is converted from a case statement to
  925. X         allow the variable characters (backspace, kill_line
  926. X         and break) to be processed.  Case statements in
  927. X         C require constants as labels, so it failed ...
  928. X      */
  929. X
  930. X        if (ch == backspace &&
  931. X          (!escaped || !isprint(ch)) ) {
  932. X          /* This is tricky. Here we are dealing with all situations
  933. X           * under which a backspace (really whatever erase char is
  934. X           * set to, not necessarily \b) erases the previous character.
  935. X           * It will erase unless escaped, because if it's escaped
  936. X           * it is taken literally. There is one exception to that --
  937. X           * if backspace would be rejected (we don't accept non-printing
  938. X           * characters in non-passwd mode), we accept it here as an
  939. X           * erasing character, for it if got rejected there would
  940. X           * be no way of erasing a preceding backslash. */
  941. X          escaped = OFF;
  942. X              if (iindex > 0) {
  943. X        iindex--;
  944. X        erase_a_char();
  945. X          }
  946. X          else {
  947. X        Writechar(' ');
  948. X        Writechar(BACKSPACE);
  949. X          }
  950. X        }
  951. X        else if (ch == '\n' || ch == '\r') {
  952. X          escaped = OFF;
  953. X          string[iindex] = '\0';
  954. X          if (cursor_control)
  955. X            transmit_functions(ON);
  956. X          return(0);
  957. X        }
  958. X        else if (ch == ctrl('W')) {
  959. X          escaped = OFF;
  960. X          if (iindex == 0)
  961. X            continue;        /* no point staying here.. */
  962. X          iindex--;
  963. X          if (isslash(string[iindex])) {
  964. X            erase_a_char();
  965. X          }
  966. X          else {
  967. X            while (iindex >= 0 && isspace(string[iindex])) {
  968. X              iindex--;
  969. X              erase_a_char();
  970. X            }
  971. X
  972. X            while (iindex >= 0 && ! isstopchar(string[iindex])) {
  973. X              iindex--;
  974. X              erase_a_char();
  975. X            }
  976. X            iindex++;/* and make sure we point at the first AVAILABLE slot */
  977. X          }
  978. X        }
  979. X        else if (ch == ctrl('R')) {
  980. X          escaped = OFF;
  981. X          string[iindex] = '\0';
  982. X          PutLine1(x,y, "%s", string);    
  983. X          CleartoEOLN();
  984. X        }
  985. X        else if (!escaped && ch == kill_line) {
  986. X          /* needed to test if escaped since kill_line character could
  987. X           * be a desired valid printing character */
  988. X          escaped = OFF;
  989. X          MoveCursor(x,y);
  990. X              CleartoEOLN();
  991. X          iindex = 0;
  992. X        }
  993. X        else if (ch == '\0') {
  994. X          escaped = OFF;
  995. X          if (cursor_control)
  996. X            transmit_functions(ON);
  997. X          fflush(stdin);     /* remove extraneous chars, if any */
  998. X          string[0] = '\0'; /* clean up string, and... */
  999. X          return(-1);
  1000. X        }
  1001. X        else if (!isprint(ch)) {
  1002. X          /* non-printing character - warn with bell*/
  1003. X          /* don't turn off escaping backslash since current character
  1004. X           * doesn't "use it up".
  1005. X           */
  1006. X          Writechar('\007');
  1007. X        }
  1008. X        else {  /* default case */
  1009. X        if(escaped && (ch == backspace || ch == kill_line)) {
  1010. X          /* if last character was a backslash,
  1011. X           * and if this character is escapable
  1012. X           * simply write this character over it even if
  1013. X           * this character is a backslash.
  1014. X           */
  1015. X          Writechar(BACKSPACE);
  1016. X          iindex--;
  1017. X          string[iindex++] = ch;
  1018. X          Writechar(ch);
  1019. X          escaped = OFF;
  1020. X        } else {
  1021. X          string[iindex++] = ch;
  1022. X          Writechar(ch);
  1023. X          escaped = ( ch == '\\' ? ON : OFF);
  1024. X        }
  1025. X        }
  1026. X    } while (iindex < SLEN);
  1027. X
  1028. X    string[iindex] = '\0';
  1029. X
  1030. X    if (cursor_control)
  1031. X      transmit_functions(ON);
  1032. X    return(0);
  1033. X}
  1034. X
  1035. Xint
  1036. XGetPrompt()
  1037. X{
  1038. X    /** This routine does a read/timeout for a single character.
  1039. X        The way that this is determined is that the routine to
  1040. X        read a character is called, then the "errno" is checked
  1041. X        against EINTR (interrupted call).  If they match, this
  1042. X        returns NO_OP_COMMAND otherwise it returns the normal
  1043. X        command.  On BSD systems, the EINTR will never be returned
  1044. X        so we instead longjmp from the signal handler.
  1045. X    **/
  1046. X
  1047. X    int ch;
  1048. X
  1049. X    if (timeout > 0) {
  1050. X      alarm((unsigned) timeout);
  1051. X#ifdef    BSD
  1052. X      if (setjmp(GetPromptBuf)) {
  1053. X        InGetPrompt = 0;
  1054. X        ch = NO_OP_COMMAND;
  1055. X        alarm((unsigned) 0);
  1056. X      }
  1057. X      else {
  1058. X        InGetPrompt = 1;
  1059. X        ch = ReadCh();
  1060. X        InGetPrompt = 0;
  1061. X        alarm((unsigned) 0);
  1062. X      }
  1063. X#else
  1064. X        errno = 0;    /* we actually have to do this.  *sigh*  */
  1065. X        ch = ReadCh();
  1066. X        if (errno == EINTR) ch = NO_OP_COMMAND;
  1067. X        alarm((unsigned) 0);
  1068. X#endif
  1069. X    }
  1070. X    else
  1071. X      ch = ReadCh();
  1072. X
  1073. X    return(ch);
  1074. X}
  1075. SHAR_EOF
  1076. chmod 0444 src/in_utils.c || echo "restore of src/in_utils.c fails"
  1077. echo "x - extracting src/init.c (Text)"
  1078. sed 's/^X//' << 'SHAR_EOF' > src/init.c &&
  1079. X
  1080. Xstatic char rcsid[] = "@(#)$Id: init.c,v 4.1 90/04/28 22:43:15 syd Exp $";
  1081. X
  1082. X/*******************************************************************************
  1083. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1084. X *
  1085. X *             Copyright (c) 1986, 1987 Dave Taylor
  1086. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1087. X *******************************************************************************
  1088. X * Bug reports, patches, comments, suggestions should be sent to:
  1089. X *
  1090. X *    Syd Weinstein, Elm Coordinator
  1091. X *    elm@DSI.COM            dsinc!elm
  1092. X *
  1093. X *******************************************************************************
  1094. X * $Log:    init.c,v $
  1095. X * Revision 4.1  90/04/28  22:43:15  syd
  1096. X * checkin of Elm 2.3 as of Release PL0
  1097. X * 
  1098. X *
  1099. X ******************************************************************************/
  1100. X
  1101. X/***** Initialize - read in all the defaults etc etc 
  1102. X*****/
  1103. X
  1104. X#include "headers.h"
  1105. X#include "patchlevel.h"
  1106. X
  1107. X#ifdef TERMIOS
  1108. X#  include <termios.h>
  1109. X   typedef struct termios term_buff;
  1110. X#else
  1111. X# ifdef TERMIO
  1112. X#  include <termio.h>
  1113. X#  define tcgetattr(fd,buf)    ioctl((fd),TCGETA,(buf))
  1114. X   typedef struct termio term_buff;
  1115. X# else
  1116. X#  include <sgtty.h>
  1117. X#  define tcgetattr(fd,buf)    ioctl((fd),TIOCGETP,(buf))
  1118. X   typedef struct sgttyb term_buff;
  1119. X# endif
  1120. X#endif
  1121. X
  1122. X#ifdef PWDINSYS
  1123. X#  include <sys/pwd.h>
  1124. X#else
  1125. X#  include <pwd.h>
  1126. X#endif
  1127. X
  1128. X#ifdef I_TIME
  1129. X#  include <time.h>
  1130. X#endif
  1131. X#ifdef I_SYSTIME
  1132. X#  include <sys/time.h>
  1133. X#endif
  1134. X
  1135. X#include <signal.h>
  1136. X#include <ctype.h>
  1137. X#include <errno.h>
  1138. X
  1139. X#ifdef BSD
  1140. X#undef toupper
  1141. X#undef tolower
  1142. X#endif
  1143. X
  1144. Xextern int errno;        /* system error number on failure */
  1145. Xextern char version_buff[];
  1146. X
  1147. Xchar *error_name(), *error_description();
  1148. X
  1149. Xchar *getenv(), *getlogin(), *strcpy(), *strcat(), *index();
  1150. Xunsigned short getgid(), getuid(); 
  1151. Xvoid exit();
  1152. X#ifndef    _POSIX_SOURCE
  1153. Xstruct passwd *getpwuid();
  1154. X#endif
  1155. Xchar *get_full_name();
  1156. X
  1157. X#ifdef VOIDSIG
  1158. X  void
  1159. X#else
  1160. X  int
  1161. X#endif
  1162. X#ifdef SIGTSTP
  1163. X    sig_user_stop(), sig_return_from_user_stop(),
  1164. X#endif
  1165. X    quit_signal(), term_signal(), ill_signal(),
  1166. X    fpe_signal(),  bus_signal(),  segv_signal(),
  1167. X    alarm_signal(), pipe_signal(), hup_signal();
  1168. X
  1169. Xinitialize(requestedmfile)
  1170. Xchar *requestedmfile;    /* first mail file to open, empty if the default */
  1171. X{
  1172. X    /** initialize the whole ball of wax.
  1173. X    **/
  1174. X    struct passwd *pass;
  1175. X    register int i, hostlen, domlen; 
  1176. X
  1177. X#if defined(SIGVEC) & defined(SV_INTERRUPT)
  1178. X    struct sigvec alarm_vec;
  1179. X#endif
  1180. X    char     buffer[SLEN], *cp;
  1181. X
  1182. X    sprintf(version_buff, "%s PL%d", VERSION, PATCHLEVEL);
  1183. X    Raw(ON);
  1184. X
  1185. X    /* save original user and group ids */
  1186. X    userid  = getuid();
  1187. X    groupid = getgid();    
  1188. X
  1189. X    /* make all newly created files private */
  1190. X    original_umask = umask(077);
  1191. X
  1192. X    /* Get username (logname), home (login directory), and full_username
  1193. X     * (part of GCOS) field from the password entry for this user id.
  1194. X     * Full_username will get overridden by fullname in elmrc, if defined.
  1195. X     */
  1196. X
  1197. X    if((pass = getpwuid(userid)) == NULL) {
  1198. X      error("You have no password entry!");
  1199. X      Raw(OFF);
  1200. X      exit(1);
  1201. X    }
  1202. X    strcpy(username, pass->pw_name);
  1203. X    strcpy(home, pass->pw_dir);
  1204. X
  1205. X    if((cp = get_full_name(username)) != NULL)
  1206. X      strcpy(full_username, cp);
  1207. X    else
  1208. X      strcpy(full_username, username);    /* fall back on logname */
  1209. X
  1210. X#ifdef DEBUG
  1211. X    if (debug) {        /* setup for dprint() statements! */
  1212. X      char newfname[SLEN], filename[SLEN];
  1213. X
  1214. X      sprintf(filename, "%s/%s", home, DEBUGFILE);
  1215. X      if (access(filename, ACCESS_EXISTS) == 0) {    /* already one! */
  1216. X        sprintf(newfname,"%s/%s", home, OLDEBUG);
  1217. X        (void) rename(filename, newfname);
  1218. X      }
  1219. X
  1220. X      /* Note what we just did up there: we always save the old
  1221. X         version of the debug file as OLDEBUG, so users can mail
  1222. X         copies of bug files without trashing 'em by starting up
  1223. X         the mailer.  Dumb, subtle, but easy enough to do!
  1224. X       */
  1225. X
  1226. X      if ((debugfile = fopen(filename, "w")) == NULL) {
  1227. X        debug = 0;    /* otherwise 'leave' will try to log! */
  1228. X        leave(fprintf(stderr,"Could not open file %s for debug output!\n",
  1229. X          filename));
  1230. X      }
  1231. X      chown(filename, userid, groupid); /* file owned by user */
  1232. X
  1233. X      fprintf(debugfile, 
  1234. X     "Debug output of the ELM program (at debug level %d).  Version %s\n\n",
  1235. X          debug, version_buff);
  1236. X    }
  1237. X#endif
  1238. X
  1239. X    /*
  1240. X     * If debug level is fairly low, ignore keyboard signals
  1241. X     * until the screen is set up.
  1242. X     */
  1243. X    if (debug < 5) {
  1244. X      signal(SIGINT,  SIG_IGN);
  1245. X      signal(SIGQUIT, SIG_IGN);
  1246. X    }
  1247. X
  1248. X    if(!check_only && !batch_only) {
  1249. X      if ((i = InitScreen()) < 0) {
  1250. X        if (i == -1) {
  1251. X          printf( 
  1252. X"Sorry, but you must specify what type of terminal you're on if you want to\n");
  1253. X          printf( 
  1254. X"run the \"elm\" program. (You need your environment variable \"TERM\" set.)\n"
  1255. X             );
  1256. X          dprint(1,(debugfile,"No $TERM variable in environment!\n"));
  1257. X        }
  1258. X        else if (i == -2) {
  1259. X          printf(
  1260. X"You need a cursor-addressable terminal to run \"elm\" and I can't find any\n");
  1261. X          printf(
  1262. X"kind of termcap entry for \"%s\" - check your \"TERM\" setting...\n",
  1263. X           getenv("TERM"));
  1264. X          dprint(1,
  1265. X        (debugfile,"$TERM variable is an unknown terminal type!\n"));
  1266. X        } else {
  1267. X          printf("Failed trying to initialize your terminal entry: unknown return code %d\n", i);
  1268. X          dprint(1, (debugfile, "Initscreen returned unknown code: %d\n",
  1269. X          i));
  1270. X        }
  1271. X        Raw(OFF);
  1272. X        exit(1);    /* all the errors share this exit statement */
  1273. X      }
  1274. X    }
  1275. X
  1276. X    if (debug < 5) {    /* otherwise let the system trap 'em! */
  1277. X      signal(SIGQUIT, quit_signal);        /* Quit signal                 */
  1278. X      signal(SIGTERM, term_signal);     /* Terminate signal         */
  1279. X      signal(SIGILL,  ill_signal);        /* Illegal instruction      */
  1280. X      signal(SIGFPE,  fpe_signal);        /* Floating point exception */
  1281. X      signal(SIGBUS,  bus_signal);        /* Bus error              */
  1282. X      signal(SIGSEGV, segv_signal);        /* Segmentation Violation   */
  1283. X      signal(SIGHUP,  hup_signal);        /* HangUp (line dropped)    */
  1284. X    }
  1285. X    else {
  1286. X      dprint(3,(debugfile,
  1287. X  "\n*** Elm-Internal Signal Handlers Disabled due to debug level %d ***\n\n",
  1288. X            debug));
  1289. X    }
  1290. X#if defined(SIGVEC) & defined(SV_INTERRUPT)
  1291. X    alarm_vec.sv_handler = alarm_signal;
  1292. X    alarm_vec.sv_flags = SV_INTERRUPT;
  1293. X    sigvec (SIGALRM, &alarm_vec, (struct sigvec *)0);    /* Process Timer Alarm        */
  1294. X#else
  1295. X    signal(SIGALRM, alarm_signal);        /* Process Timer Alarm      */
  1296. X#endif
  1297. X    signal(SIGPIPE, pipe_signal);        /* Illegal Pipe Operation   */
  1298. X#ifdef SIGTSTP
  1299. X    signal(SIGTSTP, sig_user_stop);        /* Suspend signal from tty  */
  1300. X    signal(SIGCONT, sig_return_from_user_stop);    /* Continue Process */
  1301. X#endif
  1302. X
  1303. X    get_term_chars();
  1304. X
  1305. X    /*
  1306. X     * Get the host name as per configured behavior.
  1307. X     */
  1308. X#ifdef HOSTCOMPILED
  1309. X    strncpy(hostname, HOSTNAME, sizeof(hostname) - 1);
  1310. X    hostname[sizeof(hostname) - 1] = '\0';
  1311. X#else
  1312. X    gethostname(hostname, sizeof(hostname));
  1313. X#endif
  1314. X
  1315. X    /*
  1316. X     * now get the domain name, used to build the full name
  1317. X     */
  1318. X    gethostdomain(hostdomain, sizeof(hostdomain));
  1319. X
  1320. X    /*
  1321. X     * now the tough part:
  1322. X     *    we need to make three variables out of this stuff:
  1323. X     *    hostname = just the hostname, as in bangpaths,
  1324. X     *        this is whatever the user gave us so far,
  1325. X     *        we wont change this one
  1326. X     *    hostdomain = this is the domain considered local to this
  1327. X     *        machine, and should be what we got above.
  1328. X     *    hostfullname = this is the full FQDN of this machine,
  1329. X     *        and is a strange combination of the first two.
  1330. X     *    if tail(hostname) == hostdomain
  1331. X     *        then hostfullname = hostname
  1332. X     *            ie: node.ld.domain.type, ld.domain.type -> node.ld.domain.type
  1333. X     *    else if hostname == hostdomain + 1
  1334. X     *        then hostfullname = hostname
  1335. X     *            ie: domain.type, .domain.type -> domain.type
  1336. X     *    
  1337. X     *    else hostfullname = hostname + hostdomain
  1338. X     *            ie: host, .domain.type -> host.domain.type
  1339. X     * lost yet?
  1340. X     */
  1341. X    hostlen = strlen(hostname);
  1342. X    domlen = strlen(hostdomain);
  1343. X    if (hostlen >= domlen) {
  1344. X      if (strcmp(&hostname[hostlen - domlen], hostdomain) == 0)
  1345. X        strcpy(hostfullname, hostname);
  1346. X      else {
  1347. X        strcpy(hostfullname, hostname);
  1348. X        strcat(hostfullname, hostdomain);
  1349. X      }
  1350. X    } else {
  1351. X      if (strcmp(hostname, hostdomain + 1) == 0)
  1352. X        strcpy(hostfullname, hostname);
  1353. X      else {
  1354. X        strcpy(hostfullname, hostname);
  1355. X        strcat(hostfullname, hostdomain);
  1356. X      }
  1357. X    }
  1358. X
  1359. X    /* Determine the default mail file name.
  1360. X     * 
  1361. X     * First look for an environment variable MAIL, then
  1362. X     * use then mailhome if it is not found
  1363. X     */
  1364. X    if ((cp = getenv("MAIL")) == NULL)
  1365. X        sprintf(defaultfile, "%s%s", mailhome, username);
  1366. X    else
  1367. X        strcpy(defaultfile, cp);
  1368. X
  1369. X    /* Determine options that might be set in the .elm/elmrc */
  1370. X    read_rc_file();
  1371. X
  1372. X    /* Determine the mail file to read */
  1373. X    if (*requestedmfile == '\0')
  1374. X      strcpy(requestedmfile, defaultfile);
  1375. X    else if(!expand_filename(requestedmfile, FALSE)) {
  1376. X        Raw(OFF);
  1377. X        exit(0);
  1378. X        }
  1379. X    if (check_size)
  1380. X      if(check_mailfile_size(requestedmfile) != 0) {
  1381. X          Raw(OFF);
  1382. X          exit(0);
  1383. X      }
  1384. X
  1385. X    /* check for permissions only if not send only mode file */
  1386. X    if (! mail_only) {
  1387. X      if ((errno = can_access(requestedmfile, READ_ACCESS)) != 0) {
  1388. X        if (strcmp(requestedmfile, defaultfile) != 0 || errno != ENOENT) {
  1389. X          dprint(1, (debugfile,
  1390. X            "Error: given file %s as folder - unreadable (%s)!\n", 
  1391. X            requestedmfile, error_name(errno)));
  1392. X          fprintf(stderr,"Can't open folder '%s' for reading!\n",
  1393. X            requestedmfile);
  1394. X          Raw(OFF);
  1395. X          exit(1);
  1396. X        }
  1397. X      }
  1398. X    }
  1399. X
  1400. X    /** check to see if the user has defined a LINES or COLUMNS
  1401. X        value different to that in the termcap entry (for
  1402. X        windowing systems, of course!) **/
  1403. X
  1404. X    ScreenSize(&LINES, &COLUMNS);
  1405. X
  1406. X    if ((cp = getenv("LINES")) != NULL && isdigit(*cp)) {
  1407. X      sscanf(cp, "%d", &LINES);
  1408. X      LINES -= 1;    /* kludge for HP Window system? ... */
  1409. X    }
  1410. X
  1411. X    if ((cp = getenv("COLUMNS")) != NULL && isdigit(*cp))
  1412. X      sscanf(cp, "%d", &COLUMNS);
  1413. X
  1414. X    /** fix the shell if needed **/
  1415. X
  1416. X    if (shell[0] != '/') {
  1417. X       sprintf(buffer, "/bin/%s", shell);
  1418. X       strcpy(shell, buffer);
  1419. X    }
  1420. X
  1421. X    if (! mail_only && ! check_only) {
  1422. X
  1423. X      /* get the cursor control keys... */
  1424. X
  1425. X      cursor_control = FALSE;
  1426. X
  1427. X      if ((cp = return_value_of("ku")) != NULL) {
  1428. X        strcpy(up, cp);
  1429. X        if ((cp = return_value_of("kd")) != NULL) {
  1430. X          strcpy(down, cp);
  1431. X          if ((cp = return_value_of("kl")) != NULL) {
  1432. X        strcpy(left, cp);
  1433. X        if ((cp = return_value_of("kr")) != NULL) {
  1434. X          strcpy(right, cp);
  1435. X          cursor_control = TRUE;
  1436. X          transmit_functions(ON);
  1437. X        }
  1438. X          }
  1439. X        }
  1440. X      }
  1441. X
  1442. X      strcpy(start_highlight, "->");
  1443. X      end_highlight[0] = '\0';
  1444. X
  1445. X      if (!arrow_cursor) {    /* try to use inverse bar instead */
  1446. X        if ((cp = return_value_of("so")) != NULL) {
  1447. X          strcpy(start_highlight, cp);
  1448. X          if ((cp = return_value_of("se")) == NULL)
  1449. X            strcpy(start_highlight, "->");
  1450. X          else {
  1451. X            strcpy(end_highlight, cp);
  1452. X            has_highlighting = TRUE;
  1453. X          }
  1454. X        }
  1455. X      }
  1456. X    }
  1457. X
  1458. X    /** clear the screen **/
  1459. X    if(!check_only && !batch_only)
  1460. X      ClearScreen();
  1461. X
  1462. X    if (! mail_only && ! check_only) {
  1463. X      if (mini_menu)
  1464. X        headers_per_page = LINES - 13;
  1465. X      else
  1466. X        headers_per_page = LINES -  8;    /* 5 more headers! */
  1467. X
  1468. X      newmbox(requestedmfile, FALSE);    /* read in the folder! */
  1469. X    }
  1470. X
  1471. X#ifdef DEBUG
  1472. X    if (debug >= 2 && debug < 10) {
  1473. X      fprintf(debugfile,
  1474. X"hostname = %-20s \tusername = %-20s \tfullname = %-20s\n",
  1475. X             hostname, username, full_username);
  1476. X
  1477. X      fprintf(debugfile,
  1478. X"home     = %-20s \teditor   = %-20s \trecvd_mail  = %-20s\n",
  1479. X         home, editor, recvd_mail);
  1480. X
  1481. X      fprintf(debugfile,
  1482. X"cur_folder   = %-20s \tfolders  = %-20s \tprintout = %-20s\n",
  1483. X         cur_folder, folders, printout);
  1484. X    
  1485. X      fprintf(debugfile,
  1486. X"sent_mail = %-20s \tprefix   = %-20s \tshell    = %-20s\n\n",
  1487. X        sent_mail, prefixchars, shell);
  1488. X    
  1489. X      if (local_signature[0])
  1490. X        fprintf(debugfile, "local_signature = \"%s\"\n",
  1491. X            local_signature);
  1492. X      if (remote_signature[0])
  1493. X        fprintf(debugfile, "remote_signature = \"%s\"\n",
  1494. X            remote_signature);
  1495. X      if (local_signature[0] || remote_signature[0])
  1496. X        fprintf(debugfile, "\n");
  1497. X    }
  1498. X#endif
  1499. X}
  1500. X
  1501. Xget_term_chars()
  1502. X{
  1503. X    /** This routine sucks out the special terminal characters
  1504. X        ERASE and KILL for use in the input routine.  The meaning 
  1505. X            of the characters are (dare I say it?) fairly obvious... **/
  1506. X
  1507. X    term_buff term_buffer;
  1508. X
  1509. X    if (tcgetattr(STANDARD_INPUT,&term_buffer) == -1) {
  1510. X      dprint(1, (debugfile,
  1511. X           "Error: %s encountered on ioctl call (get_term_chars)\n", 
  1512. X           error_name(errno)));
  1513. X      /* set to defaults for terminal driver */
  1514. X      backspace = BACKSPACE;
  1515. X      kill_line = ctrl('U');
  1516. X    }
  1517. X    else {
  1518. X#if defined(TERMIO) || defined(TERMIOS)
  1519. X      backspace = term_buffer.c_cc[VERASE];
  1520. X      kill_line = term_buffer.c_cc[VKILL];
  1521. X#else
  1522. X      backspace = term_buffer.sg_erase;
  1523. X      kill_line = term_buffer.sg_kill;
  1524. X#endif
  1525. X    }
  1526. X}
  1527. SHAR_EOF
  1528. chmod 0444 src/init.c || echo "restore of src/init.c fails"
  1529. echo "x - extracting src/leavembox.c (Text)"
  1530. sed 's/^X//' << 'SHAR_EOF' > src/leavembox.c &&
  1531. X
  1532. Xstatic char rcsid[] = "@(#)$Id: leavembox.c,v 4.1 90/04/28 22:43:18 syd Exp $";
  1533. X
  1534. X/*******************************************************************************
  1535. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1536. X *
  1537. X *             Copyright (c) 1986, 1987 Dave Taylor
  1538. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1539. X *******************************************************************************
  1540. X * Bug reports, patches, comments, suggestions should be sent to:
  1541. X *
  1542. X *    Syd Weinstein, Elm Coordinator
  1543. X *    elm@DSI.COM            dsinc!elm
  1544. X *
  1545. X *******************************************************************************
  1546. X * $Log:    leavembox.c,v $
  1547. X * Revision 4.1  90/04/28  22:43:18  syd
  1548. X * checkin of Elm 2.3 as of Release PL0
  1549. X * 
  1550. X *
  1551. X ******************************************************************************/
  1552. X
  1553. X/** leave current folder, updating etc. as needed...
  1554. X  
  1555. X**/
  1556. X
  1557. X#include "headers.h"
  1558. X#include <sys/types.h>
  1559. X#include <sys/stat.h>
  1560. X#ifdef LOCK_BY_FLOCK
  1561. X#include <sys/file.h>
  1562. X#endif
  1563. X#include <errno.h>
  1564. X
  1565. X/**********
  1566. X   Since a number of machines don't seem to bother to define the utimbuf
  1567. X   structure for some *very* obscure reason.... 
  1568. X
  1569. X   Suprise, though, BSD has a different utime() entirely...*sigh*
  1570. X**********/
  1571. X
  1572. X#ifndef BSD
  1573. X# ifdef NOUTIMBUF
  1574. X
  1575. Xstruct utimbuf {
  1576. X    time_t    actime;        /** access time       **/ 
  1577. X    time_t    modtime;    /** modification time **/
  1578. X       };
  1579. X
  1580. X
  1581. X# endif /* NOUTIMBUF */
  1582. X#endif /* BSD */
  1583. X
  1584. Xextern int errno;
  1585. X
  1586. Xchar *error_name(), *error_description(), *strcpy(), *rindex();
  1587. Xunsigned short getegid();
  1588. X#ifndef    _POSIX_SOURCE
  1589. Xunsigned long sleep();
  1590. X#endif
  1591. X
  1592. Xint
  1593. Xleave_mbox(resyncing, quitting, prompt)
  1594. Xint resyncing, quitting, prompt;
  1595. X{
  1596. X    /** Close folder, deleting some messages, storing others in mbox,
  1597. X        and keeping others, as directed by user input and elmrc options.
  1598. X
  1599. X        Return    1    Folder altered
  1600. X            0    Folder not altered
  1601. X            -1    New mail arrived during the process and
  1602. X                    closing was aborted.
  1603. X        If "resyncing" we are just writing out folder to reopen it. We
  1604. X        therefore only consider deletes and keeps, not stores to mbox.
  1605. X        Also we don't remove NEW status so that it can be preserved
  1606. X        across the resync.
  1607. X
  1608. X        If "quitting" and "prompt" is false, then no prompting is done.
  1609. X        Otherwise prompting is dependent upon the variable
  1610. X        question_me, as set by an elmrc option.  This behavior makes
  1611. X        the 'q' command prompt just like 'c' and '$', while
  1612. X        retaining the 'Q' command for a quick exit that never
  1613. X        prompts.
  1614. X    **/
  1615. X
  1616. X    FILE *temp;
  1617. X    char temp_keep_file[SLEN], buffer[SLEN];
  1618. X    struct stat    buf;        /* stat command  */
  1619. X#ifdef BSD
  1620. X    time_t utime_buffer[2];        /* utime command */
  1621. X#else
  1622. X    struct utimbuf utime_buffer;    /* utime command */
  1623. X#endif
  1624. X    register int to_delete = 0, to_store = 0, to_keep = 0, i,
  1625. X             marked_deleted, marked_read, marked_unread,
  1626. X             last_sortby, ask_questions,  asked_storage_q,
  1627. X             num_chgd_status, need_to_copy;
  1628. X    char answer;
  1629. X    long bytes();
  1630. X
  1631. X    dprint(1, (debugfile, "\n\n-- leaving folder --\n\n"));
  1632. X
  1633. X    if (message_count == 0)
  1634. X      return(0);    /* nothing changed */
  1635. X
  1636. X    ask_questions = ((quitting && !prompt) ? FALSE : question_me);
  1637. X
  1638. X    /* YES or NO on softkeys */
  1639. X    if (hp_softkeys && ask_questions) {
  1640. X      define_softkeys(YESNO);
  1641. X      softkeys_on();
  1642. X    }
  1643. X
  1644. X    /* Clear the exit dispositions of all messages, just in case
  1645. X     * they were left set by a previous call to this function
  1646. X     * that was interrupted by the receipt of new mail.
  1647. X     */
  1648. X    for(i = 0; i < message_count; i++)
  1649. X      headers[i]->exit_disposition = UNSET;
  1650. X      
  1651. X    /* Determine if deleted messages are really to be deleted */
  1652. X
  1653. X    /* we need to know if there are none, or one, or more to delete */
  1654. X    for (marked_deleted=0, i=0; i<message_count && marked_deleted<2; i++)
  1655. X      if (ison(headers[i]->status, DELETED))
  1656. X        marked_deleted++;
  1657. X
  1658. X        if(marked_deleted) {
  1659. X      answer = (always_del ? 'y' : 'n');    /* default answer */
  1660. X      if(ask_questions) {
  1661. X        sprintf(buffer, "Delete message%s? (y/n) ", plural(marked_deleted));
  1662. X        answer = want_to(buffer, answer);
  1663. X      }
  1664. X
  1665. X      if(answer == 'y') {
  1666. X        for (i = 0; i < message_count; i++) {
  1667. X          if (ison(headers[i]->status, DELETED)) {
  1668. X        headers[i]->exit_disposition = DELETE;
  1669. X        to_delete++;
  1670. X          }
  1671. X        }
  1672. X      }
  1673. X    }
  1674. X    dprint(3, (debugfile, "Messages to delete: %d\n", to_delete));
  1675. X
  1676. X    /* If this is a non spool file, or if we are merely resyncing,
  1677. X     * all messages with an unset disposition (i.e. not slated for
  1678. X     * deletion) are to be kept.
  1679. X     * Otherwise, we need to determine if read and unread messages
  1680. X     * are to be stored or kept.
  1681. X     */
  1682. X    if(folder_type == NON_SPOOL || resyncing) {
  1683. X      to_store = 0;
  1684. X      for (i = 0; i < message_count; i++) {
  1685. X        if(headers[i]->exit_disposition == UNSET) {
  1686. X          headers[i]->exit_disposition = KEEP;
  1687. X          to_keep++;
  1688. X        }
  1689. X      }
  1690. X    } else {
  1691. X
  1692. X      /* Let's first see if user wants to store read messages 
  1693. X       * that aren't slated for deletion */
  1694. X
  1695. X      asked_storage_q = FALSE;
  1696. X
  1697. X      /* we need to know if there are none, or one, or more marked read */
  1698. X      for (marked_read=0, i=0; i < message_count && marked_read < 2; i++) {
  1699. X        if((isoff(headers[i]->status, UNREAD))
  1700. X          && (headers[i]->exit_disposition == UNSET))
  1701. X        marked_read++;
  1702. X      }
  1703. X      if(marked_read) {
  1704. X        answer = (always_store ? 'y' : 'n');    /* default answer */
  1705. X        if(ask_questions) {
  1706. X          sprintf(buffer, "Move read message%s to \"received\" folder? (y/n) ",
  1707. X            plural(marked_read));
  1708. X          answer = want_to(buffer, answer);
  1709. X          asked_storage_q = TRUE;
  1710. X        }
  1711. X
  1712. X        for (i = 0; i < message_count; i++) {
  1713. X          if((isoff(headers[i]->status, UNREAD)) 
  1714. X        && (headers[i]->exit_disposition == UNSET)) {
  1715. X
  1716. X          if(answer == 'y') {
  1717. X            headers[i]->exit_disposition = STORE;
  1718. X            to_store++;
  1719. X          } else {
  1720. X            headers[i]->exit_disposition = KEEP;
  1721. X            to_keep++;
  1722. X          }
  1723. X          }
  1724. X        } 
  1725. X      }
  1726. X
  1727. X      /* If we asked the user if read messages should be stored,
  1728. X       * and if the user wanted them kept instead, then certainly the
  1729. X       * user would want the unread messages kept as well.
  1730. X       */
  1731. X      if(asked_storage_q && answer == 'n') {
  1732. X
  1733. X        for (i = 0; i < message_count; i++) {
  1734. X          if((ison(headers[i]->status, UNREAD))
  1735. X        && (headers[i]->exit_disposition == UNSET)) {
  1736. X          headers[i]->exit_disposition = KEEP;
  1737. X          to_keep++;
  1738. X          }
  1739. X        }
  1740. X
  1741. X      } else {
  1742. X
  1743. X        /* Determine if unread messages are to be kept */
  1744. X
  1745. X        /* we need to know if there are none, or one, or more unread */
  1746. X        for (marked_unread=0, i=0; i<message_count && marked_unread<2; i++)
  1747. X          if((ison(headers[i]->status, UNREAD))
  1748. X        && (headers[i]->exit_disposition == UNSET))
  1749. X          marked_unread++;
  1750. X
  1751. X        if(marked_unread) {
  1752. X          answer = (always_keep ? 'y' : 'n');    /* default answer */
  1753. X          if(ask_questions) {
  1754. X        sprintf(buffer,
  1755. X          "Keep unread message%s in incoming mailbox? (y/n) ",
  1756. X          plural(marked_unread));
  1757. X        answer = want_to(buffer, answer);
  1758. X          }
  1759. X
  1760. X          for (i = 0; i < message_count; i++) {
  1761. X        if((ison(headers[i]->status, UNREAD))
  1762. X          && (headers[i]->exit_disposition == UNSET)) {
  1763. X
  1764. X            if(answer == 'n') {
  1765. X              headers[i]->exit_disposition = STORE;
  1766. X              to_store++;
  1767. X            } else {
  1768. X              headers[i]->exit_disposition = KEEP;
  1769. X              to_keep++;
  1770. X            }
  1771. X          
  1772. X        }
  1773. X          }
  1774. X        }
  1775. X      }
  1776. X    }
  1777. X
  1778. X    dprint(3, (debugfile, "Messages to store: %d\n", to_store));
  1779. X    dprint(3, (debugfile, "Messages to keep: %d\n", to_keep));
  1780. X
  1781. X    if(to_delete + to_store + to_keep != message_count) {
  1782. X      dprint(1, (debugfile,
  1783. X      "Error: %d to delete + %d to store + %d to keep != %d message cnt\n",
  1784. X        to_delete, to_store, to_keep, message_count));
  1785. X      error("Something wrong in message counts! Folder unchanged.");
  1786. X      emergency_exit();
  1787. X    }
  1788. X      
  1789. X
  1790. X    /* If we are not resyncing, we are leaving the mailfile and
  1791. X     * the new messages are new no longer. Note that this changes
  1792. X     * their status.
  1793. X     */
  1794. X    if(!resyncing) {
  1795. X      for (i = 0; i < message_count; i++) {
  1796. X        if (ison(headers[i]->status, NEW)) {
  1797. X          clearit(headers[i]->status, NEW);
  1798. X          headers[i]->status_chgd = TRUE;
  1799. X        }
  1800. X      }
  1801. X    }
  1802. X
  1803. X    /* If all messages are to be kept and none have changed status
  1804. X     * we don't need to do anything because the current folder won't
  1805. X     * be changed by our writing it out - unless we are resyncing, in
  1806. X     * which case we force the writing out of the mailfile.
  1807. SHAR_EOF
  1808. echo "End of part 16"
  1809. echo "File src/leavembox.c is continued in part 17"
  1810. echo "17" > s2_seq_.tmp
  1811. exit 0
  1812.  
  1813. exit 0 # Just in case...
  1814.