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

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