home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / elm2.2 / part21 < prev    next >
Encoding:
Internet Message Format  |  1989-04-12  |  49.3 KB

  1. Subject:  v18i100:  Elm mail system, release 2.2, Part21/22
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
  7. Posting-number: Volume 18, Issue 100
  8. Archive-name: elm2.2/part21
  9.  
  10. #!/bin/sh
  11. # this is part 21 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file src/showmsg_c.c continued
  14. #
  15. CurArch=21
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file src/showmsg_c.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> src/showmsg_c.c
  27. X#else
  28. X               store_msg("Can't scan for calendar entries!");
  29. X#endif
  30. X               break;
  31. X
  32. X        case '%' : put_cmd_name("Display return address", TRUE);
  33. X               get_return(msg_line, current-1);
  34. X               break;
  35. X
  36. X        case 'b' : put_cmd_name("Bounce message", TRUE);
  37. X               remail();
  38. X               break;
  39. X  
  40. X        case 'd' : delete_msg(TRUE, FALSE); /* really delete it, silent */
  41. X               if (! resolve_mode)
  42. X             store_msg("Message marked for deletion.");
  43. X               else
  44. X             goto next_undel_msg;
  45. X               break;
  46. X
  47. X        case 'f' : put_cmd_name("Forward message", TRUE);
  48. X               if(forward()) put_border();
  49. X               break;
  50. X
  51. X        case 'g' : put_cmd_name("Group reply", TRUE);
  52. X               (void) reply_to_everyone();
  53. X               break;
  54. X
  55. X        case 'h' : screen_mangled = 0;
  56. X               if (filter) { 
  57. X                 filter = 0; 
  58. X                 intbuf = show_msg(current); 
  59. X                 filter = 1;
  60. X             return(intbuf);
  61. X               } else
  62. X                 return(show_msg(current)); 
  63. X
  64. X        case 'q' :
  65. X        case 'i' : (void) get_page(current);
  66. X               clear_error();        /* zero out pending msg   */
  67. X               if (cursor_control)
  68. X             transmit_functions(ON);
  69. X               screen_mangled = 0;
  70. X               return(0);        /* avoid <return> looping */
  71. Xnext_undel_msg :    /* a target for resolve mode actions */
  72. X
  73. X        case ' ' :
  74. X        case 'j' :
  75. X        case 'n' : screen_mangled = 0;
  76. X               if((i=next_message(current-1, TRUE)) != -1)
  77. X             return(show_msg(current = i+1));
  78. X               else return(0);
  79. X
  80. Xnext_msg:
  81. X        case 'J' : screen_mangled = 0;
  82. X               if((i=next_message(current-1, FALSE)) != -1)
  83. X             return(show_msg(current = i+1));
  84. X               else return(0);
  85. X
  86. Xprev_undel_msg:
  87. X        case 'k' : screen_mangled = 0;
  88. X               if((i=prev_message(current-1, TRUE)) != -1)
  89. X             return(show_msg(current = i+1));
  90. X               else return(0);
  91. X
  92. X        case 'K' : screen_mangled = 0;
  93. X               if((i=prev_message(current-1, FALSE)) != -1)
  94. X             return(show_msg(current = i+1));
  95. X               else return(0);
  96. X
  97. X        case 'm' : put_cmd_name("Mail message", TRUE);
  98. X               if(sendmsg("","","", TRUE, allow_forms, FALSE))
  99. X             put_border();
  100. X               break;
  101. X
  102. X        case 'p' : put_cmd_name("Print message", FALSE);
  103. X               print_msg();
  104. X               store_msg("Queued for printing.");
  105. X               break;
  106. X
  107. X        case 'r' : put_cmd_name("Reply to message", TRUE);
  108. X               if(reply()) put_border();
  109. X               break;
  110. X
  111. X        case '>' :
  112. X        case 'C' :
  113. X        case 's' : put_cmd_name((command != 'C' ? "Save" : "Copy"), TRUE);
  114. X               (void) save(&intbuf, TRUE, (command != 'C'));
  115. X               if (resolve_mode && command != 'C')
  116. X             goto next_undel_msg;
  117. X               break;
  118. X
  119. X        case 't' : istagged=tag_message(FALSE);    
  120. X               if(istagged)
  121. X             store_msg("Message tagged.");
  122. X               else 
  123. X             store_msg("Message untagged.");
  124. X               break;
  125. X
  126. X        case 'u' : undelete_msg(FALSE); /* undelete it, silently */
  127. X               if (! resolve_mode)
  128. X             store_msg("Message undeleted.");
  129. X               else {
  130. X/******************************************************************************
  131. X ** We're special casing the U)ndelete command here *not* to move to the next
  132. X ** undeleted message ; instead it'll blindly move to the next message in the
  133. X ** list.  See 'elm.c' and the command by "case 'u'" for further information.
  134. X ** The old code was:
  135. X             goto next_undel_msg;
  136. X*******************************************************************************/
  137. X             goto next_msg;
  138. X               }
  139. X               break;
  140. X
  141. X        case 'x' : fflush(stdout); leave();
  142. X        
  143. X        case ctrl('J'):
  144. X        case ctrl('M'):  screen_mangled = 0;
  145. X                 return(show_msg(current));
  146. X
  147. X
  148. X            case ESCAPE : if (cursor_control) {
  149. X  
  150. X                            key_offset = 1;
  151. X  
  152. X                            ch = ReadCh(); 
  153. X  
  154. X                            if (ch == ESCAPE)
  155. X                             ch = ReadCh();
  156. X  
  157. X                            if ( ch == '[' || ch == 'O') 
  158. X                            {
  159. X                              ch = ReadCh();
  160. X                              key_offset++;
  161. X                            }
  162. X  
  163. X                            if (ch == up[key_offset])
  164. X                  goto prev_undel_msg;
  165. X                            else if (ch == down[key_offset])
  166. X                  goto next_undel_msg;
  167. X                            else {
  168. X                  screen_mangled = 0;
  169. X                              return(0);
  170. X                }
  171. X                          }
  172. X                          else          /* Eat 2 chars for escape codes */
  173. X                          {
  174. X                            ch = ReadCh();
  175. X                            ch = ReadCh();
  176. X                            putchar((char) 007);
  177. X                            fflush(stdout);
  178. X                screen_mangled = 0;
  179. X                            return(0);
  180. X                           }
  181. X  
  182. X        default  : putchar((char) 007);    /* BEEP! */
  183. X      }
  184. X
  185. X      /* display prompt */
  186. X      if (screen_mangled) {
  187. X        /* clear what was left over from previous command 
  188. X         * and display last generated message.
  189. X         */
  190. X        put_prompt();
  191. X        CleartoEOS();
  192. X        put_help();
  193. X        Centerline(LINES, msg_line);
  194. X        MoveCursor(LINES-3, POST_PROMPT_COL);
  195. X      } else {
  196. X        /* display bottom line prompt with last generated message */
  197. X        MoveCursor(LINES, 0);
  198. X        CleartoEOS();
  199. X        StartBold();
  200. X        Write_to_screen("%s Command ('i' to return to index): ",
  201. X        1, msg_line);
  202. X        EndBold();
  203. X      }
  204. X      *msg_line = '\0';    /* null last generated message */
  205. X
  206. X      command = GetPrompt();    /* get next command from user */
  207. X    }
  208. X}
  209. X
  210. Xput_cmd_name(command, will_mangle)
  211. Xchar *command;
  212. Xint will_mangle;
  213. X{
  214. X
  215. X    /* If screen is or will be mangled display the command name 
  216. X     * and erase the bottom of the screen.
  217. X     * But first if the border line hasn't yet been drawn, draw it.
  218. X     */
  219. X    if(will_mangle && !screen_mangled) {
  220. X      build_bottom();
  221. X      screen_mangled = TRUE;
  222. X    }
  223. X    if(screen_mangled) {
  224. X      PutLine0(LINES-3, POST_PROMPT_COL, command);
  225. X      CleartoEOS();
  226. X    }
  227. X}
  228. X
  229. Xput_border()
  230. X{
  231. X     PutLine0(LINES-4, 0, 
  232. X"--------------------------------------------------------------------------\n");
  233. X}
  234. X
  235. Xbuild_bottom()
  236. X{
  237. X     MoveCursor(LINES-4, 0);
  238. X     CleartoEOS();
  239. X     put_border();
  240. X     put_prompt();
  241. X     put_help();
  242. X}
  243. SHAR_EOF
  244. echo "File src/showmsg_c.c is complete"
  245. chmod 0444 src/showmsg_c.c || echo "restore of src/showmsg_c.c fails"
  246. echo "x - extracting src/signals.c (Text)"
  247. sed 's/^X//' << 'SHAR_EOF' > src/signals.c &&
  248. X
  249. Xstatic char rcsid[] = "@(#)$Id: signals.c,v 2.5 89/03/25 21:47:23 syd Exp $";
  250. X
  251. X/*******************************************************************************
  252. X *  The Elm Mail System  -  $Revision: 2.5 $   $State: Exp $
  253. X *
  254. X *             Copyright (c) 1986, 1987 Dave Taylor
  255. X *             Copyright (c) 1988, 1989 USENET Community Trust
  256. X *******************************************************************************
  257. X * Bug reports, patches, comments, suggestions should be sent to:
  258. X *
  259. X *    Syd Weinstein, Elm Coordinator
  260. X *    elm@dsinc.UUCP            dsinc!elm
  261. X *
  262. X *******************************************************************************
  263. X * $Log:    signals.c,v $
  264. X * Revision 2.5  89/03/25  21:47:23  syd
  265. X * Initial 2.2 Release checkin
  266. X * 
  267. X *
  268. X ******************************************************************************/
  269. X
  270. X/** This set of routines traps various signals and informs the
  271. X    user of the error, leaving the program in a nice, graceful
  272. X    manner.
  273. X
  274. X**/
  275. X
  276. X#include "headers.h"
  277. X#include <signal.h>
  278. X
  279. Xextern int pipe_abort;        /* set to TRUE if receive SIGPIPE */
  280. X
  281. Xquit_signal()
  282. X{
  283. X    dprint(1, (debugfile, "\n\n** Received SIGQUIT **\n\n\n\n"));
  284. X    leave();
  285. X}
  286. X
  287. Xhup_signal()
  288. X{
  289. X    dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n"));
  290. X    leave();
  291. X}
  292. X
  293. Xterm_signal() 
  294. X{
  295. X    dprint(1, (debugfile, "\n\n** Received SIGTERM **\n\n\n\n"));
  296. X    leave();
  297. X}
  298. X
  299. Xill_signal()
  300. X{
  301. X    dprint(1, (debugfile, "\n\n** Received SIGILL **\n\n\n\n"));
  302. X    PutLine0(LINES, 0, "\n\nIllegal Instruction signal!\n\n");
  303. X    emergency_exit();
  304. X}
  305. X
  306. Xfpe_signal()  
  307. X{
  308. X    dprint(1, (debugfile, "\n\n** Received SIGFPE **\n\n\n\n"));
  309. X    PutLine0(LINES, 0,"\n\nFloating Point Exception signal!\n\n");
  310. X    emergency_exit();
  311. X}
  312. X
  313. Xbus_signal()
  314. X{
  315. X    dprint(1, (debugfile, "\n\n** Received SIGBUS **\n\n\n\n"));
  316. X    PutLine0(LINES, 0,"\n\nBus Error signal!\n\n");
  317. X    emergency_exit();
  318. X}
  319. X
  320. Xsegv_signal()
  321. X{
  322. X    dprint(1, (debugfile,"\n\n** Received SIGSEGV **\n\n\n\n"));
  323. X    PutLine0(LINES, 0,"\n\nSegment Violation signal!\n\n");
  324. X    emergency_exit();
  325. X}
  326. X
  327. X#ifdef VOIDSIG
  328. Xvoid alarm_signal()
  329. X#else
  330. Xint alarm_signal()
  331. X#endif
  332. X{    
  333. X    /** silently process alarm signal for timeouts... **/
  334. X
  335. X#ifdef VOIDSIG
  336. X    void alarm_signal();
  337. X#else
  338. X    int alarm_signal();
  339. X#endif
  340. X
  341. X    signal(SIGALRM, alarm_signal);
  342. X}
  343. X
  344. X#ifdef VOIDSIG
  345. Xvoid pipe_signal()
  346. X#else
  347. Xint pipe_signal()
  348. X#endif
  349. X{
  350. X    /** silently process pipe signal... **/
  351. X
  352. X#ifdef VOIDSIG
  353. X    void pipe_signal();
  354. X#else
  355. X    int pipe_signal();
  356. X#endif
  357. X
  358. X    dprint(2, (debugfile, "*** received SIGPIPE ***\n\n"));
  359. X    
  360. X    pipe_abort = TRUE;    /* internal signal ... wheeee!  */
  361. X
  362. X    signal(SIGPIPE, pipe_signal);
  363. X}
  364. X
  365. X#ifdef SIGTSTP
  366. Xint was_in_raw_state;
  367. X
  368. X#ifdef VOIDSIG
  369. Xvoid sig_user_stop()
  370. X#else
  371. Xint sig_user_stop()
  372. X#endif
  373. X{
  374. X    /* This is called when the user presses a ^Z to stop the
  375. X       process within BSD 
  376. X    */
  377. X    if (signal(SIGTSTP, SIG_DFL) != SIG_DFL)
  378. X      signal(SIGTSTP, SIG_DFL);
  379. X
  380. X    was_in_raw_state = RawState();
  381. X    Raw(OFF);    /* turn it off regardless */
  382. X
  383. X    printf("\n\nStopped.  Use \"fg\" to return to ELM\n\n");
  384. X
  385. X    kill(0, SIGSTOP);
  386. X}
  387. X
  388. Xsig_return_from_user_stop()
  389. X{
  390. X    /** this is called when returning from a ^Z stop **/
  391. X
  392. X#ifdef VOIDSIG
  393. X    void sig_user_stop();
  394. X#else
  395. X    int sig_user_stop();
  396. X#endif
  397. X
  398. X    if (signal(SIGTSTP, sig_user_stop) == SIG_DFL)
  399. X      signal(SIGTSTP, sig_user_stop);
  400. X
  401. X    printf(
  402. X     "\nBack in ELM. (You might need to explicitly request a redraw.)\n\n");
  403. X
  404. X    if (was_in_raw_state)
  405. X      Raw(ON);
  406. X}
  407. X#endif
  408. SHAR_EOF
  409. chmod 0444 src/signals.c || echo "restore of src/signals.c fails"
  410. echo "x - extracting src/softkeys.c (Text)"
  411. sed 's/^X//' << 'SHAR_EOF' > src/softkeys.c &&
  412. X
  413. Xstatic char rcsid[] = "@(#)$Id: softkeys.c,v 2.8 89/03/25 21:47:25 syd Exp $";
  414. X
  415. X/*******************************************************************************
  416. X *  The Elm Mail System  -  $Revision: 2.8 $   $State: Exp $
  417. X *
  418. X *             Copyright (c) 1986, 1987 Dave Taylor
  419. X *             Copyright (c) 1988, 1989 USENET Community Trust
  420. X *******************************************************************************
  421. X * Bug reports, patches, comments, suggestions should be sent to:
  422. X *
  423. X *    Syd Weinstein, Elm Coordinator
  424. X *    elm@dsinc.UUCP            dsinc!elm
  425. X *
  426. X *******************************************************************************
  427. X * $Log:    softkeys.c,v $
  428. X * Revision 2.8  89/03/25  21:47:25  syd
  429. X * Initial 2.2 Release checkin
  430. X * 
  431. X *
  432. X ******************************************************************************/
  433. X
  434. X
  435. X#include "headers.h"
  436. X
  437. Xdefine_softkeys(level)
  438. Xint level;
  439. X{
  440. X    if (! hp_softkeys) return;
  441. X
  442. X    if (level == MAIN) {
  443. X
  444. X      define_key(f1, "  Display  Msg",   "\r");
  445. X      define_key(f2, "  Mail     Msg",   "m");
  446. X      define_key(f3, "  Reply  to Msg",  "r");
  447. X
  448. X      if (user_level == 0) {
  449. X        define_key(f4, "  Save     Msg",   "s");
  450. X        define_key(f5, " Delete    Msg",   "d");
  451. X        define_key(f6, "Undelete   Msg",   "u");
  452. X         }
  453. X      else {
  454. X        define_key(f4, " Change  Folder", "c");
  455. X        define_key(f5, "  Save     Msg",   "s");
  456. X        define_key(f6, " Delete/Undelete", "^");
  457. X      }
  458. X
  459. X      define_key(f7, " Print     Msg",   "p");
  460. X      define_key(f8, "  Quit     ELM",   "q");
  461. X    }
  462. X    else if (level == ALIAS) {
  463. X      define_key(f1, " Alias  Current",  "a");
  464. X      define_key(f2, " Check  Person",   "p");
  465. X      define_key(f3, " Check  System",   "s");
  466. X      define_key(f4, " Make    Alias",   "m");
  467. X      clear_key(f5);
  468. X      clear_key(f6);
  469. X      clear_key(f7);
  470. X      define_key(f8, " Return  to ELM",  "r");
  471. X    }
  472. X    else if (level == YESNO) {
  473. X      define_key(f1, "  Yes",  "y");
  474. X      clear_key(f2);
  475. X      clear_key(f3);
  476. X      clear_key(f4);
  477. X      clear_key(f5);
  478. X      clear_key(f6);
  479. X      clear_key(f7);
  480. X      define_key(f8, "   No",  "n");
  481. X    }
  482. X    else if (level == READ) {
  483. X      define_key(f1, "  Next    Page  ", " ");
  484. X      clear_key(f2);
  485. X      define_key(f3, "  Next    Msg   ", "j");
  486. X      define_key(f4, "  Prev    Msg   ", "k");
  487. X      define_key(f5, "  Reply  to Msg ", "r");
  488. X      define_key(f6, " Delete   Msg   ", "d");
  489. X      define_key(f7, "  Send    Msg   ", "m");
  490. X      define_key(f8, " Return  to ELM ", "q");
  491. X    }
  492. X    else if (level == CHANGE) {
  493. X      define_key(f1, "  Mail  Directry", "=/");
  494. X      define_key(f2, "  Home  Directry", "~/");
  495. X      clear_key(f3);
  496. X      define_key(f4, "Incoming Mailbox", "!\n");
  497. X      define_key(f5, "\"Received\" Folder", ">\n");
  498. X      define_key(f6, "\"Sent\"   Folder ", "<\n");
  499. X      clear_key(f7);
  500. X      define_key(f8, " Cancel", "\n");
  501. X    }
  502. X
  503. X    softkeys_on();
  504. X}
  505. X
  506. Xdefine_key(key, display, send)
  507. Xint key;
  508. Xchar *display, *send;
  509. X{
  510. X
  511. X    char buffer[30];
  512. X
  513. X    sprintf(buffer,"%s%s", display, send);
  514. X
  515. X    fprintf(stderr, "%c&f%dk%dd%dL%s", ESCAPE, key,
  516. X        strlen(display), strlen(send), buffer);
  517. X    fflush(stdout);
  518. X}
  519. X
  520. Xsoftkeys_on()    
  521. X{ 
  522. X    /* enable (esc&s1A) turn on softkeys (esc&jB) and turn on MENU 
  523. X       and USER/SYSTEM options. */
  524. X
  525. X    if (hp_softkeys) {
  526. X      fprintf(stderr, "%c&s1A%c&jB%c&jR", ESCAPE, ESCAPE, ESCAPE); 
  527. X      fflush(stdout);
  528. X    }
  529. X    
  530. X}
  531. X
  532. Xsoftkeys_off()    
  533. X{ 
  534. X    /* turn off softkeys (esc&j@) */
  535. X
  536. X    if (hp_softkeys) {
  537. X      fprintf(stderr, "%c&s0A%c&j@", ESCAPE, ESCAPE); 
  538. X      fflush(stdout);
  539. X    }
  540. X}
  541. X
  542. Xclear_key(key)  
  543. X{     
  544. X    /** set a key to nothing... **/
  545. X
  546. X    if (hp_softkeys) 
  547. X       define_key(key, "                ", ""); 
  548. X}
  549. SHAR_EOF
  550. chmod 0444 src/softkeys.c || echo "restore of src/softkeys.c fails"
  551. echo "x - extracting src/sort.c (Text)"
  552. sed 's/^X//' << 'SHAR_EOF' > src/sort.c &&
  553. X
  554. Xstatic char rcsid[] = "@(#)$Id: sort.c,v 2.7 89/03/25 21:47:26 syd Exp $";
  555. X
  556. X/*******************************************************************************
  557. X *  The Elm Mail System  -  $Revision: 2.7 $   $State: Exp $
  558. X *
  559. X *             Copyright (c) 1986, 1987 Dave Taylor
  560. X *             Copyright (c) 1988, 1989 USENET Community Trust
  561. X *******************************************************************************
  562. X * Bug reports, patches, comments, suggestions should be sent to:
  563. X *
  564. X *    Syd Weinstein, Elm Coordinator
  565. X *    elm@dsinc.UUCP            dsinc!elm
  566. X *
  567. X *******************************************************************************
  568. X * $Log:    sort.c,v $
  569. X * Revision 2.7  89/03/25  21:47:26  syd
  570. X * Initial 2.2 Release checkin
  571. X * 
  572. X *
  573. X ******************************************************************************/
  574. X
  575. X/** Sort folder header table by the field specified in the global
  576. X    variable "sortby"...if we're sorting by something other than
  577. X    the default SENT_DATE, also put some sort of indicator on the
  578. X    screen.
  579. X
  580. X**/
  581. X
  582. X#include "headers.h"
  583. X
  584. Xchar *sort_name(), *skip_re();
  585. Xvoid   qsort();
  586. X
  587. Xsort_mailbox(entries, visible)
  588. Xint entries, visible;
  589. X{
  590. X    /** Sort the header_table definitions... If 'visible', then
  591. X        put the status lines etc **/
  592. X    
  593. X    int last_index = -1;
  594. X    int compare_headers();    /* for sorting */
  595. X
  596. X    dprint(2, (debugfile, "\n** sorting folder by %s **\n\n", 
  597. X        sort_name(FULL)));
  598. X
  599. X    /* Don't get last_index if no entries or no current. */
  600. X    /* There would be no current if we are sorting a new mail file. */
  601. X    if (entries > 0 && current > 0)
  602. X      last_index = headers[current-1]->index_number;
  603. X
  604. X    if (entries > 30 && visible)  
  605. X      error1("Sorting messages by %s...", sort_name(FULL));
  606. X    
  607. X    qsort(headers, (unsigned) entries, sizeof (struct header_rec *),
  608. X          compare_headers);
  609. X
  610. X    if (last_index > -1)
  611. X      find_old_current(last_index);
  612. X
  613. X    clear_error();
  614. X}
  615. X
  616. Xint
  617. Xcompare_headers(p1, p2)
  618. Xstruct header_rec **p1, **p2;
  619. X{
  620. X    /** compare two headers according to the sortby value.
  621. X
  622. X        Sent Date uses a routine to compare two dates,
  623. X        Received date is keyed on the file offsets (think about it)
  624. X        Sender uses the truncated from line, same as "build headers",
  625. X        and size and subject are trivially obvious!!
  626. X        (actually, subject has been modified to ignore any leading
  627. X        patterns [rR][eE]*:[ \t] so that replies to messages are
  628. X        sorted with the message (though a reply will always sort to
  629. X        be 'greater' than the basenote)
  630. X     **/
  631. X
  632. X    char from1[SLEN], from2[SLEN];    /* sorting buffers... */
  633. X    struct header_rec *first, *second;
  634. X    int ret;
  635. X    
  636. X    first = *p1;
  637. X    second = *p2;
  638. X
  639. X    switch (abs(sortby)) {
  640. X    case SENT_DATE:
  641. X        ret = compare_dates(first, second);
  642. X        break;
  643. X
  644. X    case RECEIVED_DATE:
  645. X        ret = compare_parsed_dates(first->received, second->received);
  646. X        break;
  647. X
  648. X    case SENDER:
  649. X        tail_of(first->from, from1, first->to);
  650. X        tail_of(second->from, from2, second->to);
  651. X        ret = strcmp(from1, from2);
  652. X        break;
  653. X
  654. X    case SIZE:
  655. X        ret = (first->lines - second->lines);
  656. X        break;
  657. X
  658. X    case MAILBOX_ORDER:
  659. X        ret = (first->index_number - second->index_number);
  660. X        break;
  661. X
  662. X    case SUBJECT:
  663. X        /* need some extra work 'cause of STATIC buffers */
  664. X        strcpy(from1, skip_re(shift_lower(first->subject)));
  665. X        ret = strcmp(from1, skip_re(shift_lower(second->subject)));
  666. X        break;
  667. X
  668. X    case STATUS:
  669. X        ret = (first->status - second->status);
  670. X        break;
  671. X
  672. X    default:
  673. X        /* never get this! */
  674. X        ret = 0;
  675. X        break;
  676. X    }
  677. X
  678. X    if (sortby < 0)
  679. X      ret = -ret;
  680. X
  681. X    return ret;
  682. X}
  683. X
  684. Xchar *sort_name(type)
  685. Xint type;
  686. X{
  687. X    /** return the name of the current sort option...
  688. X        type can be "FULL", "SHORT" or "PAD"
  689. X    **/
  690. X    int pad, abr;
  691. X    
  692. X    pad = (type == PAD);
  693. X    abr = (type == SHORT);
  694. X
  695. X    if (sortby < 0) {
  696. X      switch (- sortby) {
  697. X        case SENT_DATE    : return( 
  698. X                      pad?     "Reverse Date Mail Sent  " : 
  699. X                  abr?     "Reverse-Sent" :
  700. X                       "Reverse Date Mail Sent");
  701. X        case RECEIVED_DATE: return(
  702. X                  abr?     "Reverse-Received":
  703. X                  "Reverse Date Mail Rec'vd" );
  704. X
  705. X        case MAILBOX_ORDER: return(
  706. X                  pad?     "Reverse Mailbox Order   " :
  707. X                  abr?     "Reverse-Mailbox":
  708. X                           "Reverse Mailbox Order");
  709. X
  710. X        case SENDER       : return(
  711. X                  pad?     "Reverse Message Sender  " : 
  712. X                  abr?     "Reverse-From":
  713. X                       "Reverse Message Sender");
  714. X        case SIZE         : return(
  715. X                  abr?     "Reverse-Lines" : 
  716. X                       "Reverse Lines in Message");
  717. X        case SUBJECT      : return(
  718. X                  pad?     "Reverse Message Subject " : 
  719. X                  abr?     "Reverse-Subject" : 
  720. X                       "Reverse Message Subject");
  721. X        case STATUS          : return(
  722. X                  pad?     "Reverse Message Status  " :
  723. X                  abr?     "Reverse-Status":
  724. X                           "Reverse Message Status");
  725. X      }
  726. X    }
  727. X    else {
  728. X      switch (sortby) {
  729. X        case SENT_DATE    : return( 
  730. X                        pad?   "Date Mail Sent          " : 
  731. X                        abr?   "Sent" : 
  732. X                       "Date Mail Sent");
  733. X        case RECEIVED_DATE: return(
  734. X                            pad?   "Date Mail Rec'vd        " :
  735. X                            abr?   "Received" :
  736. X                       "Date Mail Rec'vd");
  737. X        case MAILBOX_ORDER: return(
  738. X                            pad?   "Mailbox Order           " :
  739. X                            abr?   "Mailbox" :
  740. X                                   "Mailbox Order");
  741. X        case SENDER       : return(
  742. X                    pad?   "Message Sender          " : 
  743. X                    abr?   "From" : 
  744. X                       "Message Sender");
  745. X        case SIZE         : return(
  746. X                    pad?   "Lines in Message        " :
  747. X                    abr?   "Lines" :
  748. X                           "Lines in Message");
  749. X        case SUBJECT      : return(
  750. X                    pad?   "Message Subject         " : 
  751. X                    abr?   "Subject" : 
  752. X                       "Message Subject");
  753. X        case STATUS          : return(
  754. X                    pad?   "Message Status          " :
  755. X                    abr?   "Status" :
  756. X                           "Message Status");
  757. X      }
  758. X    }
  759. X
  760. X    return("*UNKNOWN-SORT-PARAMETER*");
  761. X}
  762. X
  763. Xfind_old_current(iindex)
  764. Xint iindex;
  765. X{
  766. X    /** Set current to the message that has "index" as it's 
  767. X        index number.  This is to track the current message
  768. X        when we resync... **/
  769. X
  770. X    register int i;
  771. X
  772. X    dprint(4, (debugfile, "find-old-current(%d)\n", iindex));
  773. X
  774. X    for (i = 0; i < message_count; i++)
  775. X      if (headers[i]->index_number == iindex) {
  776. X        current = i+1;
  777. X        dprint(4, (debugfile, "\tset current to %d!\n", current));
  778. X        return;
  779. X      }
  780. X
  781. X    dprint(4, (debugfile, 
  782. X        "\tcouldn't find current index.  Current left as %d\n",
  783. X        current));
  784. X    return;        /* can't be found.  Leave it alone, then */
  785. X}
  786. X
  787. Xchar *skip_re(string)
  788. Xchar *string;
  789. X{
  790. X    /** this routine returns the given string minus any sort of
  791. X        "re:" prefix.  specifically, it looks for, and will
  792. X        remove, any of the pattern:
  793. X
  794. X        ( [Rr][Ee][^:]:[ ] ) *
  795. X
  796. X        If it doesn't find a ':' in the line it will return it
  797. X        intact, just in case!
  798. X    **/
  799. X
  800. X    static char buffer[SLEN];
  801. X    register int i=0;
  802. X
  803. X    while (whitespace(string[i])) i++;
  804. X
  805. X    do {
  806. X      if (string[i] == '\0') return( (char *) string);    /* forget it */
  807. X
  808. X      if (string[i] != 'r' || string[i+1] != 'e') 
  809. X        return( (char *) string);                /*   ditto   */
  810. X
  811. X      i += 2;    /* skip the "re" */
  812. X
  813. X      while (string[i] != ':') 
  814. X        if (string[i] == '\0')
  815. X          return( (char *) string);              /* no colon in string! */
  816. X        else
  817. X          i++;
  818. X
  819. X      /* now we've gotten to the colon, skip to the next non-whitespace  */
  820. X
  821. X      i++;    /* past the colon */
  822. X
  823. X      while (whitespace(string[i])) i++;
  824. X
  825. X    } while (string[i] == 'r' && string[i+1] == 'e');
  826. X    /* and now copy it into the buffer and sent it along... */
  827. X
  828. X    strcpy(buffer, (char *) string + i);
  829. X
  830. X    return( (char *) buffer);
  831. X}
  832. SHAR_EOF
  833. chmod 0444 src/sort.c || echo "restore of src/sort.c fails"
  834. echo "x - extracting src/string2.c (Text)"
  835. sed 's/^X//' << 'SHAR_EOF' > src/string2.c &&
  836. X
  837. Xstatic char rcsid[] = "@(#)$Id: string2.c,v 2.3 89/03/25 21:47:28 syd Exp $";
  838. X
  839. X/*******************************************************************************
  840. X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
  841. X *
  842. X *             Copyright (c) 1986, 1987 Dave Taylor
  843. X *             Copyright (c) 1988, 1989 USENET Community Trust
  844. X *******************************************************************************
  845. X * Bug reports, patches, comments, suggestions should be sent to:
  846. X *
  847. X *    Syd Weinstein, Elm Coordinator
  848. X *    elm@dsinc.UUCP            dsinc!elm
  849. X *
  850. X *******************************************************************************
  851. X * $Log:    string2.c,v $
  852. X * Revision 2.3  89/03/25  21:47:28  syd
  853. X * Initial 2.2 Release checkin
  854. X * 
  855. X *
  856. X ******************************************************************************/
  857. X
  858. X/** This file contains string functions that are shared throughout the
  859. X    various ELM utilities...
  860. X
  861. X**/
  862. X
  863. X#ifndef TRUE
  864. X#define TRUE        1
  865. X#define FALSE        0
  866. X#endif
  867. X
  868. X#define whitespace(c)        (c == ' ' || c == '\t')
  869. X
  870. Xint 
  871. Xin_string(buffer, pattern)
  872. Xchar *buffer, *pattern;
  873. X{
  874. X    /** Returns TRUE iff pattern occurs IN IT'S ENTIRETY in buffer. **/ 
  875. X
  876. X    register int i = 0, j = 0;
  877. X    
  878. X    while (buffer[i] != '\0') {
  879. X      while (buffer[i++] == pattern[j++]) 
  880. X        if (pattern[j] == '\0') 
  881. X          return(TRUE);
  882. X      i = i - j + 1;
  883. X      j = 0;
  884. X    }
  885. X    return(FALSE);
  886. X}
  887. X
  888. Xint
  889. Xchloc(string, ch)
  890. Xchar *string, ch;
  891. X{
  892. X    /** returns the index of ch in string, or -1 if not in string **/
  893. X    register int i;
  894. X
  895. X    for (i=0; i<strlen(string); i++)
  896. X      if (string[i] == ch) return(i);
  897. X    return(-1);
  898. X}
  899. X
  900. Xint
  901. Xoccurances_of(ch, string)
  902. Xchar ch, *string;
  903. X{
  904. X    /** returns the number of occurances of 'ch' in string 'string' **/
  905. X
  906. X    register int count = 0, i;
  907. X
  908. X    for (i=0; i<strlen(string); i++)
  909. X      if (string[i] == ch) count++;
  910. X
  911. X    return(count);
  912. X}
  913. X
  914. Xremove_possible_trailing_spaces(string)
  915. Xchar *string;
  916. X{
  917. X    /** an incredibly simple routine that will read backwards through
  918. X        a string and remove all trailing whitespace.
  919. X    **/
  920. X
  921. X    register int i;
  922. X
  923. X    for (i=strlen(string)-1; whitespace(string[i]); i--)
  924. X        /** spin backwards **/
  925. X
  926. X    string[i+1] = '\0';    /* note that even in the worst case when there
  927. X                   are no trailing spaces at all, we'll simply
  928. X                   end up replacing the existing '\0' with
  929. X                   another one!  No worries, as M.G. would say
  930. X                */
  931. X}
  932. SHAR_EOF
  933. chmod 0444 src/string2.c || echo "restore of src/string2.c fails"
  934. echo "x - extracting src/strings.c (Text)"
  935. sed 's/^X//' << 'SHAR_EOF' > src/strings.c &&
  936. X
  937. Xstatic char rcsid[] = "@(#)$Id: strings.c,v 2.10 89/03/25 21:47:29 syd Exp $";
  938. X
  939. X/*******************************************************************************
  940. X *  The Elm Mail System  -  $Revision: 2.10 $   $State: Exp $
  941. X *
  942. X *             Copyright (c) 1986, 1987 Dave Taylor
  943. X *             Copyright (c) 1988, 1989 USENET Community Trust
  944. X *******************************************************************************
  945. X * Bug reports, patches, comments, suggestions should be sent to:
  946. X *
  947. X *    Syd Weinstein, Elm Coordinator
  948. X *    elm@dsinc.UUCP            dsinc!elm
  949. X *
  950. X *******************************************************************************
  951. X * $Log:    strings.c,v $
  952. X * Revision 2.10  89/03/25  21:47:29  syd
  953. X * Initial 2.2 Release checkin
  954. X * 
  955. X *
  956. X ******************************************************************************/
  957. X
  958. X/** This file contains all the string oriented functions for the
  959. X    ELM Mailer, and lots of other generally useful string functions! 
  960. X
  961. X    For BSD systems, this file also includes the function "tolower"
  962. X    to translate the given character from upper case to lower case.
  963. X
  964. X**/
  965. X
  966. X#include "headers.h"
  967. X#include <ctype.h>
  968. X
  969. X#ifdef BSD
  970. X#undef tolower
  971. X#undef toupper
  972. X#endif
  973. X
  974. X/** forward declarations **/
  975. X
  976. Xchar *format_long(), *strip_commas(), *tail_of_string(), *shift_lower(),
  977. X     *get_token(), *strip_parens(), *argv_zero(), *strcpy(), *strncpy();
  978. X
  979. X
  980. Xcopy_sans_escape(dest, source, len)
  981. Xchar *dest, *source;
  982. Xint  len;
  983. X{
  984. X    /** this performs the same function that strncpy() does, but
  985. X        also will translate any escape character to a printable
  986. X        format (e.g. ^(char value + 32))
  987. X    **/
  988. X
  989. X    register int i = 0, j = 0;
  990. X
  991. X    while (i < len && source[i] != '\0') {
  992. X      if (iscntrl(source[i]) && source[i] != '\t') {
  993. X         dest[j++] = '^';
  994. X         dest[j++] = source[i++] + 'A' - 1;
  995. X      }
  996. X      else
  997. X        dest[j++] = source[i++];
  998. X    }
  999. X
  1000. X    dest[j] = '\0';
  1001. X}
  1002. X
  1003. Xint
  1004. Xtail_of(from, buffer, to)
  1005. Xchar *from, *buffer, *to;
  1006. X{
  1007. X    /** Return last two words of 'from'.  This is to allow
  1008. X        painless display of long return addresses as simply the
  1009. X        machine!username. 
  1010. X        Or if the first word of the 'from' address is username or
  1011. X        full_username and 'to' is not NULL, then use the 'to' line
  1012. X        instead of the 'from' line.
  1013. X        If the 'to' line is used, return 1, else return 0.
  1014. X
  1015. X        Also modified to know about X.400 addresses (sigh) and
  1016. X        that when we ask for the tail of an address similar to
  1017. X        a%b@c we want to get back a@b ...
  1018. X    **/
  1019. X
  1020. X    /** Note: '!' delimits Usenet nodes, '@' delimits ARPA nodes,
  1021. X              ':' delimits CSNet & Bitnet nodes, '%' delimits multi-
  1022. X          stage ARPA hops, and '/' delimits X.400 addresses...
  1023. X              (it is fortunate that the ASCII character set only has
  1024. X             so many metacharacters, as I think we're probably using
  1025. X          them all!!) **/
  1026. X
  1027. X    register int loc, i = 0, cnt = 0, using_to = 0;
  1028. X    
  1029. X#ifndef INTERNET
  1030. X    
  1031. X    /** let's see if we have an address appropriate for hacking: 
  1032. X        what this actually does is remove the spuriously added
  1033. X        local bogus Internet header if we have one and the message
  1034. X        has some sort of UUCP component too...
  1035. X    **/
  1036. X
  1037. X    sprintf(buffer, "@%s%s", hostname, hostdomain);
  1038. X    if (chloc(from,'!') != -1 && in_string(from, buffer))
  1039. X       from[strlen(from)-strlen(buffer)] = '\0';
  1040. X
  1041. X#endif
  1042. X
  1043. X    for (loc = strlen(from)-1; loc >= 0 && cnt < 2; loc--) {
  1044. X      if (from[loc] == BANG || from[loc] == AT_SIGN ||
  1045. X          from[loc] == COLON) cnt++;
  1046. X      if (cnt < 2) buffer[i++] = from[loc];
  1047. X    }
  1048. X
  1049. X    buffer[i] = '\0';
  1050. X
  1051. X    reverse(buffer);
  1052. X
  1053. X    if ((strncmp(buffer, username, strlen(username)) == 0) ||
  1054. X      (strncmp(buffer, full_username, strlen(full_username)) == 0)) {
  1055. X
  1056. X      /* This message is from the user, so use the "to" header instead
  1057. X       * if possible, to be more informative. Otherwise be nice and
  1058. X       * use full_username rather than the bare username even if
  1059. X       * we've only matched on the bare username.
  1060. X       */
  1061. X
  1062. X      if(to && *to != '\0') {
  1063. X        tail_of(to, buffer, (char *)0);
  1064. X        using_to = 1;
  1065. X      } else
  1066. X        strcpy(buffer, full_username);
  1067. X
  1068. X    } else {                    /* user%host@host? */
  1069. X
  1070. X      /** The logic here is that we're going to use 'loc' as a handy
  1071. X          flag to indicate if we've hit a '%' or not.  If we have,
  1072. X          we'll rewrite it as an '@' sign and then when we hit the
  1073. X          REAL at sign (we must have one) we'll simply replace it
  1074. X          with a NULL character, thereby ending the string there.
  1075. X      **/
  1076. X
  1077. X      loc = 0;
  1078. X
  1079. X      for (i=0; buffer[i] != '\0'; i++)
  1080. X        if (buffer[i] == '%') {
  1081. X          buffer[i] = AT_SIGN;
  1082. X          loc++;
  1083. X        }
  1084. X        else if (buffer[i] == AT_SIGN && loc)
  1085. X          buffer[i] = '\0';
  1086. X    }
  1087. X    return(using_to);
  1088. X
  1089. X}
  1090. X
  1091. Xchar *format_long(inbuff, init_len)
  1092. Xchar *inbuff;
  1093. Xint   init_len;
  1094. X{
  1095. X    /** Return buffer with \n\t sequences added at each point where it 
  1096. X        would be more than 80 chars long.  It only allows the breaks at 
  1097. X        legal points (ie commas followed by white spaces).  init-len is 
  1098. X        the characters already on the first line...  Changed so that if 
  1099. X            this is called while mailing without the overhead of "elm", it'll 
  1100. X            include "\r\n\t" instead.
  1101. X        Changed to use ',' as a separator and to REPLACE it after it's
  1102. X        found in the output stream...
  1103. X    **/
  1104. X
  1105. X    static char ret_buffer[VERY_LONG_STRING];
  1106. X    register int iindex = 0, current_length = 0, depth=15, i;
  1107. X    char     buffer[VERY_LONG_STRING];
  1108. X    char     *word, *bufptr;
  1109. X
  1110. X    strcpy(buffer, inbuff);
  1111. X
  1112. X    bufptr = (char *) buffer;
  1113. X
  1114. X    current_length = init_len + 2;    /* for luck */
  1115. X
  1116. X    while ((word = get_token(bufptr,",", depth)) != NULL) {
  1117. X
  1118. X        /* first, decide what sort of separator we need, if any... */
  1119. X
  1120. X      if (strlen(word) + current_length > 80) {
  1121. X        if (iindex > 0) {
  1122. X          ret_buffer[iindex++] = ',';    /* close 'er up, doctor! */
  1123. X          ret_buffer[iindex++] = '\n';
  1124. X          ret_buffer[iindex++] = '\t';
  1125. X        }
  1126. X        
  1127. X        /* now add this pup! */
  1128. X
  1129. X        for (i=(word[0] == ' '? 1:0); i<strlen(word); i++)
  1130. X          ret_buffer[iindex++] = word[i];
  1131. X        current_length = strlen(word) + 8;    /* 8 = TAB */
  1132. X      }
  1133. X
  1134. X      else {    /* just add this address to the list.. */
  1135. X
  1136. X        if (iindex > 0) {
  1137. X          ret_buffer[iindex++] = ',';    /* comma added! */
  1138. X          ret_buffer[iindex++] = ' ';
  1139. X          current_length += 2;
  1140. X        }
  1141. X        for (i=(word[0] == ' '? 1:0); i<strlen(word); i++)
  1142. X          ret_buffer[iindex++] = word[i];
  1143. X        current_length += strlen(word);
  1144. X      }
  1145. X    
  1146. X      bufptr = NULL;
  1147. X    }
  1148. X    
  1149. X    ret_buffer[iindex] = '\0';
  1150. X
  1151. X    return( (char *) ret_buffer);
  1152. X}
  1153. X
  1154. Xchar *strip_commas(string)
  1155. Xchar *string;
  1156. X{
  1157. X    /** return string with all commas changed to spaces.  This IS
  1158. X        destructive and will permanently change the input string.. **/
  1159. X
  1160. X    register int i;
  1161. X
  1162. X    for (i=0; i < strlen(string); i++)
  1163. X      if (string[i] == COMMA)
  1164. X        string[i] = SPACE;
  1165. X
  1166. X    return( (char *) string);
  1167. X}
  1168. X
  1169. Xchar *strip_parens(string)
  1170. Xchar *string;
  1171. X{
  1172. X    /** Return string with all parenthesized information removed.
  1173. X        This is a non-destructive algorithm... **/
  1174. X
  1175. X    static char  buffer[VERY_LONG_STRING];
  1176. X    register int i, depth = 0, buffer_index = 0;
  1177. X
  1178. X    for (i=0; i < strlen(string); i++) {
  1179. X      if (string[i] == '(')
  1180. X        depth++;
  1181. X      else if (string[i] == ')') 
  1182. X        depth--;
  1183. X      else if (depth == 0)
  1184. X        buffer[buffer_index++] = string[i];
  1185. X    }
  1186. X    
  1187. X    buffer[buffer_index] = '\0';
  1188. X
  1189. X    return( (char *) buffer);
  1190. X}
  1191. X
  1192. Xmove_left(string, chars)
  1193. Xchar string[];
  1194. Xint  chars;
  1195. X{
  1196. X    /** moves string chars characters to the left DESTRUCTIVELY **/
  1197. X
  1198. X    register int i;
  1199. X
  1200. X    /*  chars--; /* index starting at zero! */
  1201. X
  1202. X    for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  1203. X      string[i-chars] = string[i];
  1204. X
  1205. X    string[i-chars] = '\0';
  1206. X}
  1207. X
  1208. Xremove_first_word(string)
  1209. Xchar *string;
  1210. X{    /** removes first word of string, ie up to first non-white space
  1211. X        following a white space! **/
  1212. X
  1213. X    register int loc;
  1214. X
  1215. X    for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  1216. X        ;
  1217. X
  1218. X    while (string[loc] == ' ' || string[loc] == '\t')
  1219. X      loc++;
  1220. X    
  1221. X    move_left(string, loc);
  1222. X}
  1223. X
  1224. Xsplit_word(buffer, first, rest)
  1225. Xchar *buffer, *first, *rest;
  1226. X{
  1227. X    /** Rip the buffer into first word and rest of word, translating it
  1228. X        all to lower case as we go along..
  1229. X    **/
  1230. X
  1231. X    register int i, j = 0;
  1232. X
  1233. X    /** skip leading white space, just in case.. **/
  1234. X
  1235. X    for (i=0; whitespace(buffer[i]); i++)    ;
  1236. X
  1237. X    /** now copy into 'first' until we hit white space or EOLN **/
  1238. X
  1239. X    for (j=0; i < strlen(buffer) && ! whitespace(buffer[i]); ++i)
  1240. X      first[j++] = tolower(buffer[i]);
  1241. X
  1242. X    first[j] = '\0';
  1243. X    
  1244. X    while (whitespace(buffer[i])) i++;
  1245. X
  1246. X    for (j=0; i < strlen(buffer); i++)
  1247. X      rest[j++] = tolower(buffer[i]);
  1248. X
  1249. X    rest[j] = '\0';
  1250. X
  1251. X    return;
  1252. X}
  1253. X
  1254. Xchar *tail_of_string(string, maxchars)
  1255. Xchar *string;
  1256. Xint  maxchars;
  1257. X{
  1258. X    /** Return a string that is the last 'maxchars' characters of the
  1259. X        given string.  This is only used if the first word of the string
  1260. X        is longer than maxchars, else it will return what is given to
  1261. X        it... 
  1262. X    **/
  1263. X
  1264. X    static char buffer[SLEN];
  1265. X    register int iindex, i;
  1266. X
  1267. X    for (iindex=0;! whitespace(string[iindex]) && iindex < strlen(string); 
  1268. X         iindex++)
  1269. X      ;
  1270. X
  1271. X    if (iindex < maxchars) {
  1272. X      strncpy(buffer, string, maxchars-2);    /* word too short */
  1273. X      buffer[maxchars-2] = '.';
  1274. X      buffer[maxchars-1] = '.';
  1275. X      buffer[maxchars]   = '.';
  1276. X      buffer[maxchars+1] = '\0';
  1277. X    } 
  1278. X    else {
  1279. X      i = maxchars;
  1280. X      buffer[i--] = '\0';
  1281. X      while (i > 1) 
  1282. X        buffer[i--] = string[iindex--];
  1283. X      buffer[2] = '.';
  1284. X      buffer[1] = '.';
  1285. X      buffer[0] = '.';
  1286. X    }
  1287. X
  1288. X    return( (char *) buffer);
  1289. X}
  1290. X
  1291. Xreverse(string)
  1292. Xchar *string;
  1293. X{
  1294. X    /** reverse string... pretty trivial routine, actually! **/
  1295. X
  1296. X    char buffer[SLEN];
  1297. X    register int i, j = 0;
  1298. X
  1299. X    for (i = strlen(string)-1; i >= 0; i--)
  1300. X      buffer[j++] = string[i];
  1301. X
  1302. X    buffer[j] = '\0';
  1303. X
  1304. X    strcpy(string, buffer);
  1305. X}
  1306. X
  1307. Xint
  1308. Xget_word(buffer, start, word)
  1309. Xchar *buffer, *word;
  1310. Xint start;
  1311. X{
  1312. X    /**    return next word in buffer, starting at 'start'.
  1313. X        delimiter is space or end-of-line.  Returns the
  1314. X        location of the next word, or -1 if returning
  1315. X        the last word in the buffer.  -2 indicates empty
  1316. X        buffer!  **/
  1317. X
  1318. X    register int loc = 0;
  1319. X
  1320. X    while (buffer[start] == ' ' && buffer[start] != '\0')
  1321. X      start++;
  1322. X
  1323. X    if (buffer[start] == '\0') return(-2);     /* nothing IN buffer! */
  1324. X
  1325. X    while (buffer[start] != ' ' && buffer[start] != '\0')
  1326. X      word[loc++] = buffer[start++];
  1327. X
  1328. X    word[loc] = '\0';
  1329. X    return(start);
  1330. X}
  1331. X
  1332. Xchar *shift_lower(string)
  1333. Xchar *string;
  1334. X{
  1335. X    /** return 'string' shifted to lower case.  Do NOT touch the
  1336. X        actual string handed to us! **/
  1337. X
  1338. X    static char buffer[SLEN];
  1339. X    register int i;
  1340. X
  1341. X    for (i=0; i < strlen(string); i++)
  1342. X      if (isupper(string[i]))
  1343. X        buffer[i] = tolower(string[i]);
  1344. X      else
  1345. X        buffer[i] = string[i];
  1346. X    
  1347. X    buffer[strlen(string)] = 0;
  1348. X    
  1349. X    return( (char *) buffer);
  1350. X}
  1351. X
  1352. XCenterline(line, string)
  1353. Xint line;
  1354. Xchar *string;
  1355. X{
  1356. X    /** Output 'string' on the given line, centered. **/
  1357. X
  1358. X    register int length, col;
  1359. X
  1360. X    length = strlen(string);
  1361. X
  1362. X    if (length > COLUMNS)
  1363. X      col = 0;
  1364. X    else
  1365. X      col = (COLUMNS - length) / 2;
  1366. X
  1367. X    PutLine0(line, col, string);
  1368. X}
  1369. X
  1370. Xchar *argv_zero(string)
  1371. Xchar *string;
  1372. X{
  1373. X    /** given a string of the form "/something/name" return a
  1374. X        string of the form "name"... **/
  1375. X
  1376. X    static char buffer[NLEN];
  1377. X    register int i, j=0;
  1378. X
  1379. X    for (i=strlen(string)-1; string[i] != '/'; i--)
  1380. X      buffer[j++] = string[i];
  1381. X    buffer[j] = '\0';
  1382. X
  1383. X    reverse(buffer);
  1384. X
  1385. X    return( (char *) buffer);
  1386. X}
  1387. X
  1388. X#define MAX_RECURSION        20        /* up to 20 deep recursion */
  1389. X
  1390. Xchar *get_token(source, keys, depth)
  1391. Xchar *source, *keys;
  1392. Xint   depth;
  1393. X{
  1394. X    /** This function is similar to strtok() (see "opt_utils")
  1395. X        but allows nesting of calls via pointers... 
  1396. X    **/
  1397. X
  1398. X    register int  last_ch;
  1399. X    static   char *buffers[MAX_RECURSION];
  1400. X    char     *return_value, *sourceptr;
  1401. X
  1402. X    if (depth > MAX_RECURSION) {
  1403. X       error1("Get_token calls nested greater than %d deep!", 
  1404. X          MAX_RECURSION);
  1405. X       emergency_exit();
  1406. X    }
  1407. X
  1408. X    if (source != NULL)
  1409. X      buffers[depth] = source;
  1410. X    
  1411. X    sourceptr = buffers[depth];
  1412. X    
  1413. X    if (*sourceptr == '\0') 
  1414. X      return(NULL);        /* we hit end-of-string last time!? */
  1415. X
  1416. X    sourceptr += strspn(sourceptr, keys);      /* skip the bad.. */
  1417. X    
  1418. X    if (*sourceptr == '\0') {
  1419. X      buffers[depth] = sourceptr;
  1420. X      return(NULL);            /* we've hit end-of-string   */
  1421. X    }
  1422. X
  1423. X    last_ch = strcspn(sourceptr, keys);   /* end of good stuff   */
  1424. X
  1425. X    return_value = sourceptr;          /* and get the ret     */
  1426. X
  1427. X    sourceptr += last_ch;              /* ...value            */
  1428. X
  1429. X    if (*sourceptr != '\0')        /** don't forget if we're at end! **/
  1430. X      sourceptr++;                  
  1431. X    
  1432. X    return_value[last_ch] = '\0';          /* ..ending right      */
  1433. X
  1434. X    buffers[depth] = sourceptr;          /* save this, mate!    */
  1435. X
  1436. X    return((char *) return_value);         /* and we're outta here! */
  1437. X}
  1438. SHAR_EOF
  1439. chmod 0444 src/strings.c || echo "restore of src/strings.c fails"
  1440. echo "x - extracting src/syscall.c (Text)"
  1441. sed 's/^X//' << 'SHAR_EOF' > src/syscall.c &&
  1442. X
  1443. Xstatic char rcsid[] = "@(#)$Id: syscall.c,v 2.14 89/03/25 21:47:31 syd Exp $";
  1444. X
  1445. X/*******************************************************************************
  1446. X *  The Elm Mail System  -  $Revision: 2.14 $   $State: Exp $
  1447. X *
  1448. X *             Copyright (c) 1986, 1987 Dave Taylor
  1449. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1450. X *******************************************************************************
  1451. X * Bug reports, patches, comments, suggestions should be sent to:
  1452. X *
  1453. X *    Syd Weinstein, Elm Coordinator
  1454. X *    elm@dsinc.UUCP            dsinc!elm
  1455. X *
  1456. X *******************************************************************************
  1457. X * $Log:    syscall.c,v $
  1458. X * Revision 2.14  89/03/25  21:47:31  syd
  1459. X * Initial 2.2 Release checkin
  1460. X * 
  1461. X *
  1462. X ******************************************************************************/
  1463. X
  1464. X/** These routines are used for user-level system calls, including the
  1465. X    '!' command and the '|' commands...
  1466. X
  1467. X**/
  1468. X
  1469. X#include "headers.h"
  1470. X
  1471. X#include <signal.h>
  1472. X
  1473. X#ifdef BSD
  1474. X#  include <sys/wait.h>
  1475. X#endif
  1476. X
  1477. Xchar *argv_zero();    
  1478. Xvoid  _exit();
  1479. X
  1480. Xint
  1481. Xsubshell()
  1482. X{
  1483. X    /** spawn a subshell with either the specified command
  1484. X        returns non-zero if screen rewrite needed
  1485. X    **/
  1486. X
  1487. X    char command[SLEN];
  1488. X    int  ret;
  1489. X    int  old_raw;
  1490. X
  1491. X    PutLine0(LINES-3,COLUMNS-40,"(Use the shell name for a shell.)");
  1492. X    PutLine0(LINES-2,0,"Shell command: ");
  1493. X    command[0] = '\0';
  1494. X    (void) optionally_enter(command, LINES-2, 15, FALSE, FALSE);
  1495. X    if (strlen(command) == 0) {
  1496. X      MoveCursor(LINES-2,0);    CleartoEOLN();
  1497. X      return(0);
  1498. X    }
  1499. X
  1500. X    MoveCursor(LINES,0);     CleartoEOLN();
  1501. X    if (( old_raw = RawState()) == ON)
  1502. X      Raw(OFF);
  1503. X    if (cursor_control)  transmit_functions(OFF);
  1504. X    
  1505. X    ret = system_call(command, USER_SHELL, TRUE);
  1506. X
  1507. X    PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
  1508. X
  1509. X    if (old_raw == ON)
  1510. X      Raw(ON);
  1511. X    (void) getchar();
  1512. X    if (cursor_control)  transmit_functions(ON);
  1513. X
  1514. X    if (ret != 0) error1("Return code was %d.", ret);
  1515. X    return(1);
  1516. X}
  1517. X
  1518. Xsystem_call(string, shell_type, allow_signals)
  1519. Xchar *string;
  1520. Xint   shell_type, allow_signals;
  1521. X{
  1522. X    /** execute 'string', setting uid to userid... **/
  1523. X    /** if shell-type is "SH" /bin/sh is used regardless of the 
  1524. X        users shell setting.  Otherwise, "USER_SHELL" is sent.
  1525. X        If allow_signals is TRUE, then allow the executed
  1526. X        command handle interrupt and hangup in its
  1527. X        own way. This is useful for executed programs with
  1528. X        user interaction that handle those signals on their
  1529. X        own terms. It is especially important for vi, so that
  1530. X        a message being edited when a user connection is
  1531. X        dropped is recovered by vi's expreserve program **/
  1532. X
  1533. X    int stat = 0, pid, w;
  1534. X#ifdef BSD
  1535. X    union wait status;
  1536. X#else
  1537. X    int status;
  1538. X#endif
  1539. X#ifdef VOIDSIG
  1540. X    register void (*istat)(), (*qstat)();
  1541. X# ifdef SIGTSTP
  1542. X#  ifndef BSD
  1543. X    register void (*oldstop)(), (*oldstart)();
  1544. X#  endif
  1545. X# endif
  1546. X#else
  1547. X    register int (*istat)(), (*qstat)();
  1548. X# ifdef SIGTSTP
  1549. X#  ifndef BSD
  1550. X    register int (*oldstop)(), (*oldstart)();
  1551. X#  endif
  1552. X# endif 
  1553. X#endif
  1554. X    
  1555. X    dprint(2, (debugfile,
  1556. X        "System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell,
  1557. X        string));
  1558. X
  1559. X    if ((pid = vfork()) == 0) {
  1560. X      setgid(groupid);    /* and group id            */
  1561. X      setuid(userid);    /* back to the normal user! */
  1562. X
  1563. X      if(allow_signals) {
  1564. X        /* program to exec should handle interrupt, accidental hangup, and stop signals */
  1565. X        (void)signal(SIGHUP, SIG_DFL);
  1566. X        (void)signal(SIGINT, SIG_DFL);
  1567. X#ifdef SIGTSTP
  1568. X# ifndef BSD
  1569. X        (void)signal(SIGTSTP, SIG_DFL);
  1570. X        (void)signal(SIGCONT, SIG_DFL);
  1571. X# endif
  1572. X#endif
  1573. X      } else {
  1574. X        /* program to exec should ignore interrupt, accidental hangup, and stop signals */
  1575. X        (void)signal(SIGHUP, SIG_IGN);
  1576. X        (void)signal(SIGINT, SIG_IGN);
  1577. X#ifdef SIGTSTP
  1578. X# ifndef BSD
  1579. X        (void)signal(SIGTSTP, SIG_IGN);
  1580. X        (void)signal(SIGCONT, SIG_IGN);
  1581. X# endif
  1582. X#endif
  1583. X      }
  1584. X
  1585. X      if (strlen(shell) > 0 && shell_type == USER_SHELL) {
  1586. X        execl(shell, argv_zero(shell), "-c", string, (char *) 0);
  1587. X      }
  1588. X      else 
  1589. X        execl("/bin/sh", "sh", "-c", string, (char *) 0);
  1590. X      _exit(127);
  1591. X    }
  1592. X
  1593. X    istat = signal(SIGINT, SIG_IGN);
  1594. X    qstat = signal(SIGQUIT, SIG_IGN);
  1595. X#ifdef SIGTSTP
  1596. X# ifndef BSD
  1597. X    oldstop = signal(SIGTSTP, SIG_IGN);
  1598. X    oldstart = signal(SIGCONT, SIG_IGN);
  1599. X# endif
  1600. X#endif
  1601. X
  1602. X    while ((w = wait(&status)) != pid && w != -1)
  1603. X        ;
  1604. X
  1605. X#ifdef BSD
  1606. X    if (status.w_retcode != 0) stat = status.w_retcode;
  1607. X#else
  1608. X    if (w == -1) stat = status;
  1609. X#endif
  1610. X    
  1611. X    (void)signal(SIGINT, istat);
  1612. X    (void)signal(SIGQUIT, qstat);
  1613. X#ifdef SIGTSTP
  1614. X# ifndef BSD
  1615. X    (void)signal(SIGTSTP, oldstop);
  1616. X    (void)signal(SIGCONT, oldstart);
  1617. X# endif
  1618. X#endif
  1619. X
  1620. X    return(stat);
  1621. X}
  1622. X
  1623. Xint
  1624. Xdo_pipe()
  1625. X{
  1626. X    /** pipe the current message or tagged messages to
  1627. X        the specified sequence.. **/
  1628. X
  1629. X    char command[SLEN], buffer[SLEN], message_list[SLEN];
  1630. X    register int  ret, to_pipe = 0, i;
  1631. X    int    old_raw;
  1632. X
  1633. X    message_list[0] = '\0';    /* NULL string to start... */
  1634. X
  1635. X    for (i=0; i < message_count; i++)
  1636. X      if (ison(headers[i]->status, TAGGED)) {
  1637. X        sprintf(message_list,"%s %d", message_list, 
  1638. X            headers[i]->index_number);
  1639. X        to_pipe++;
  1640. X      }
  1641. X
  1642. X    if (!to_pipe) {
  1643. X      sprintf(message_list,"%d", headers[current-1]->index_number);
  1644. X      to_pipe = 1;
  1645. X    }
  1646. X    sprintf(buffer, "Pipe message%s to: ", plural(to_pipe));
  1647. X        PutLine0(LINES-2,0,buffer);
  1648. X
  1649. X    command[0] = '\0';
  1650. X
  1651. X    (void) optionally_enter(command, LINES-2, strlen(buffer), FALSE, FALSE);
  1652. X    if (strlen(command) == 0) {
  1653. X      MoveCursor(LINES-2,0);    CleartoEOLN();
  1654. X      return(0);
  1655. X    }
  1656. X
  1657. X    MoveCursor(LINES,0);     CleartoEOLN();
  1658. X    if (( old_raw = RawState()) == ON)
  1659. X      Raw(OFF);
  1660. X
  1661. X    if (cursor_control)  transmit_functions(OFF);
  1662. X    
  1663. X    sprintf(buffer, "%s -f %s -h %s | %s",
  1664. X        readmsg,
  1665. X        (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  1666. X        message_list,
  1667. X        command);
  1668. X    
  1669. X    ret = system_call(buffer, USER_SHELL, TRUE);
  1670. X
  1671. X    PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
  1672. X    if (old_raw == ON)
  1673. X       Raw(ON);
  1674. X    (void) getchar();
  1675. X    if (cursor_control)  transmit_functions(ON);
  1676. X
  1677. X    if (ret != 0) error1("Return code was %d.", ret);
  1678. X    return(1);
  1679. X}
  1680. X
  1681. Xprint_msg()
  1682. X{
  1683. X    /** Print current message or tagged messages using 'printout' 
  1684. X        variable.  Error message iff printout not defined! **/
  1685. X
  1686. X    char buffer[SLEN], filename[SLEN], printbuffer[SLEN];
  1687. X    char message_list[SLEN];
  1688. X    register int  retcode, to_print = 0, i;
  1689. X
  1690. X    if (strlen(printout) == 0) {
  1691. X      error("Don't know how to print - option \"printmail\" undefined!");
  1692. X      return;
  1693. X    }
  1694. X    
  1695. X    message_list[0] = '\0';    /* reset to null... */
  1696. X
  1697. X    for (i=0; i < message_count; i++) 
  1698. X      if (headers[i]->status & TAGGED) {
  1699. X        sprintf(message_list, "%s %d", message_list, 
  1700. X            headers[i]->index_number);
  1701. X        to_print++;
  1702. X      }
  1703. X
  1704. X    if (! to_print) {
  1705. X      sprintf(message_list," %d", headers[current-1]->index_number);
  1706. X      to_print = 1;
  1707. X    }
  1708. X
  1709. X    sprintf(filename,"%s%d", temp_print, getpid());
  1710. X
  1711. X    if (in_string(printout, "%s"))
  1712. X      sprintf(printbuffer, printout, filename);
  1713. X    else
  1714. X      sprintf(printbuffer, "%s %s", printout, filename);
  1715. X
  1716. X    sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
  1717. X        readmsg,
  1718. X        (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  1719. X        message_list, 
  1720. X        filename,
  1721. X        printbuffer);
  1722. X    
  1723. X    dprint(2, (debugfile, "Printing system call...\n"));
  1724. X
  1725. X      Centerline(LINES, "Queuing...");
  1726. X
  1727. X    if ((retcode = system_call(buffer, SH, FALSE)) == 0) {
  1728. X      sprintf(buffer, "Message%s queued up to print.", plural(to_print));
  1729. X      Centerline(LINES, buffer);
  1730. X    }
  1731. X    else
  1732. X      error1("Printout failed with return code %d.", retcode);
  1733. X
  1734. X    unlink(filename);    /* remove da temp file! */
  1735. X}
  1736. X
  1737. Xlist_folders(numlines, helpmsg)
  1738. Xunsigned numlines;
  1739. Xchar *helpmsg;
  1740. X{
  1741. X    /** list the folders in the users FOLDERHOME directory.  This is
  1742. X        simply a call to "ls -C"
  1743. X        Numlines is the number of lines to scroll afterwards. This is
  1744. X        useful when a portion of the screen needs to be cleared for
  1745. X        subsequent prompts, but you don't want to overwrite the
  1746. X        list of folders.
  1747. X        Helpmsg is what should be printed before the listing if not NULL.
  1748. X    **/
  1749. X
  1750. X    char buffer[SLEN];
  1751. X
  1752. X    Raw(OFF);
  1753. X    ClearScreen();
  1754. X    MoveCursor(LINES, 0);
  1755. X    if(helpmsg)
  1756. X      printf(helpmsg);
  1757. X    sprintf(buffer, "cd %s;ls -C", folders);
  1758. X    printf("\n\rContents of your folder directory:\n\r\n\r");
  1759. X    system_call(buffer, SH, FALSE); 
  1760. X    while(numlines--)
  1761. X        printf("\n\r");
  1762. X    Raw(ON);
  1763. X}
  1764. SHAR_EOF
  1765. chmod 0444 src/syscall.c || echo "restore of src/syscall.c fails"
  1766. echo "x - extracting src/utils.c (Text)"
  1767. sed 's/^X//' << 'SHAR_EOF' > src/utils.c &&
  1768. X
  1769. Xstatic char rcsid[] = "@(#)$Id: utils.c,v 2.22 89/03/25 21:47:33 syd Exp $";
  1770. X
  1771. X/*******************************************************************************
  1772. X *  The Elm Mail System  -  $Revision: 2.22 $   $State: Exp $
  1773. X *
  1774. X *             Copyright (c) 1986, 1987 Dave Taylor
  1775. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1776. X *******************************************************************************
  1777. X * Bug reports, patches, comments, suggestions should be sent to:
  1778. X *
  1779. X *    Syd Weinstein, Elm Coordinator
  1780. X *    elm@dsinc.UUCP            dsinc!elm
  1781. X *
  1782. X *******************************************************************************
  1783. X * $Log:    utils.c,v $
  1784. X * Revision 2.22  89/03/25  21:47:33  syd
  1785. X * Initial 2.2 Release checkin
  1786. X * 
  1787. X *
  1788. X ******************************************************************************/
  1789. X
  1790. X/** Utility routines for ELM 
  1791. X
  1792. X**/
  1793. X
  1794. X#include "headers.h"
  1795. X#include <sys/types.h>
  1796. X#include <sys/stat.h>
  1797. X#include <ctype.h>
  1798. X#include <errno.h>
  1799. X
  1800. X#ifdef BSD
  1801. X#undef tolower
  1802. X#endif
  1803. X
  1804. X#include <signal.h>
  1805. X
  1806. Xextern int errno;
  1807. X
  1808. Xchar *error_name();
  1809. Xvoid   exit();
  1810. X
  1811. Xcreate_new_folders()
  1812. X{
  1813. X    /* this creates a new folders directory */
  1814. X
  1815. X    char source[SLEN];
  1816. X    char com[SLEN];
  1817. X
  1818. X
  1819. X    /** Some systems don't have a mkdir call - how inconvienient! **/
  1820. X
  1821. X#ifdef MKDIR
  1822. X    (void) mkdir(folders, 0700);
  1823. X#else
  1824. X    sprintf(com, "mkdir %s", folders);
  1825. X    system_call(com, SH, FALSE);
  1826. X    sprintf(com, "chmod 700 %s", folders);
  1827. X    system_call(com, SH, FALSE);
  1828. X#endif /* MKDIR */
  1829. X
  1830. X    chown( source, userid, groupid);
  1831. X}
  1832. X
  1833. Xcreate_new_elmdir()
  1834. X{
  1835. X    /** this routine is just for allowing new users who don't have the
  1836. X        old elm files to create a new .elm directory **/
  1837. X
  1838. X    char source[SLEN];
  1839. X    char com[SLEN];
  1840. X
  1841. X
  1842. X    /** Some systems don't have a mkdir call - how inconvienient! **/
  1843. X
  1844. X#ifdef MKDIR
  1845. X    sprintf(source, "%s/.elm", home);
  1846. X    (void) mkdir(source, 0700);
  1847. X#else
  1848. X    sprintf(com, "mkdir %s/.elm", home);
  1849. X    system_call(com, SH, FALSE);
  1850. X    sprintf(com, "chmod 700 %s/.elm", home);
  1851. X    system_call(com, SH, FALSE);
  1852. X#endif /* MKDIR */
  1853. X
  1854. X    chown( source, userid, groupid);
  1855. X}
  1856. X
  1857. Xmove_old_files_to_new()
  1858. X{
  1859. X    /** this routine is just for allowing people to transition from
  1860. X        the old Elm, where things are all kept in their $HOME dir,
  1861. X        to the new one where everything is in $HOME/.elm... **/
  1862. X
  1863. X    char source[SLEN], dest[SLEN], temp[SLEN];
  1864. X    char com[SLEN];
  1865. X
  1866. X    /** simply go through all the files... **/
  1867. X
  1868. X    sprintf(source, "%s/.alias_text", home);
  1869. X    if (access(source, ACCESS_EXISTS) != -1) {
  1870. X      sprintf(dest,   "%s/%s", home, ALIAS_TEXT);
  1871. X      printf("\n\rCopying from: %s\n\rCopying to:   %s\n\r", source, dest);
  1872. X    
  1873. X      sprintf(temp, "/tmp/%d", getpid());
  1874. X      sprintf(com, "%s -e 's/:/=/g' %s > %s\n", sed_cmd, source, temp);
  1875. X      (void) system_call(com, SH, FALSE);
  1876. X      sprintf(com, "%s %s %s\n", move_cmd, temp, dest);
  1877. X      (void) system_call(com, SH, FALSE);
  1878. X      (void) system_call("newalias", SH, FALSE);
  1879. X    }
  1880. X
  1881. X    sprintf(source, "%s/.elmheaders", home);
  1882. X    if (access(source, ACCESS_EXISTS) != -1) {
  1883. X      sprintf(dest,   "%s/%s", home, mailheaders);
  1884. X      printf("\n\rCopying from: %s\n\rCopying to:   %s\n\r", source, dest);
  1885. X      copy(source, dest);
  1886. X    }
  1887. X
  1888. X    sprintf(source, "%s/.elmrc", home);
  1889. X    if (access(source, ACCESS_EXISTS) != -1) {
  1890. X      sprintf(dest,   "%s/%s", home, elmrcfile);
  1891. X      printf("\n\rCopying from: %s\n\rCopying to:   %s\n\r", source, dest);
  1892. X      copy(source, dest);
  1893. X    }
  1894. X
  1895. X    printf(
  1896. X    "\n\rWelcome to the new version of ELM!\n\n\rHit return to continue.");
  1897. X    getchar();
  1898. X}
  1899. X    
  1900. Xshow_mailfile_stats()
  1901. X{
  1902. X    /** when we're about to die, let's try to dump lots of good stuff
  1903. X        to the debug file... **/
  1904. X
  1905. X    struct stat buffer;
  1906. X
  1907. X    if (debug == 0) return;        /* Damn!  Can't do it! */
  1908. X
  1909. X    if (fstat(fileno(mailfile), &buffer) == 0) {
  1910. SHAR_EOF
  1911. echo "End of part 21"
  1912. echo "File src/utils.c is continued in part 22"
  1913. echo "22" > s2_seq_.tmp
  1914. exit 0
  1915.  
  1916.