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

  1. Subject:  v22i082:  ELM mail syste, release 2.3, Part24/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 4eb49da1 1fd21ca1 8aa2115d 95ac623e
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 82
  8. Archive-name: elm2.3/part24
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 24 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file utils/answer.c continued
  15. #
  16. CurArch=24
  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 utils/answer.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> utils/answer.c
  28. X  changing the character buffer to an array of character buffers....
  29. X****/
  30. X
  31. X#define MAX_RECURSION        20        /* up to 20 deep recursion */
  32. X
  33. X#undef  NULL
  34. X#define NULL            (char *) 0    /* for this routine only   */
  35. X
  36. Xextern char *strpbrk();
  37. X
  38. Xchar *get_token(string, sepset, depth)
  39. Xchar *string, *sepset;
  40. Xint  depth;
  41. X{
  42. X
  43. X    /** string is the string pointer to break up, sepstr are the
  44. X        list of characters that can break the line up and depth
  45. X        is the current nesting/recursion depth of the call **/
  46. X
  47. X    register char    *p, *q, *r;
  48. X    static char    *savept[MAX_RECURSION];
  49. X
  50. X    /** is there space on the recursion stack? **/
  51. X
  52. X    if (depth >= MAX_RECURSION) {
  53. X     fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n",
  54. X            MAX_RECURSION);
  55. X     exit(1);
  56. X    }
  57. X
  58. X    /* set up the pointer for the first or subsequent call */
  59. X    p = (string == NULL)? savept[depth]: string;
  60. X
  61. X    if(p == 0)        /* return if no tokens remaining */
  62. X        return(NULL);
  63. X
  64. X    q = p + strspn(p, sepset);    /* skip leading separators */
  65. X
  66. X    if (*q == '\0')        /* return if no tokens remaining */
  67. X        return(NULL);
  68. X
  69. X    if ((r = strpbrk(q, sepset)) == NULL)    /* move past token */
  70. X        savept[depth] = 0;    /* indicate this is last token */
  71. X    else {
  72. X        *r = '\0';
  73. X        savept[depth] = ++r;
  74. X    }
  75. X    return(q);
  76. X}
  77. X
  78. Xchar *strip_parens(string)
  79. Xchar *string;
  80. X{
  81. X    /** Return string with all parenthesized information removed.
  82. X        This is a non-destructive algorithm... **/
  83. X
  84. X    static char  buffer[LONG_STRING];
  85. X    register int depth = 0, buffer_index = 0;
  86. X
  87. X    for (; *string; string++) {
  88. X      if (*string == '(')
  89. X        depth++;
  90. X      else if (*string == ')') 
  91. X        depth--;
  92. X      else if (depth == 0)
  93. X        buffer[buffer_index++] = *string;
  94. X    }
  95. X    
  96. X    buffer[buffer_index] = '\0';
  97. X
  98. X    return( (char *) buffer);
  99. X}
  100. SHAR_EOF
  101. echo "File utils/answer.c is complete"
  102. chmod 0444 utils/answer.c || echo "restore of utils/answer.c fails"
  103. echo "x - extracting utils/arepdaem.c (Text)"
  104. sed 's/^X//' << 'SHAR_EOF' > utils/arepdaem.c &&
  105. X
  106. Xstatic char rcsid[] = "@(#)$Id: arepdaem.c,v 4.1 90/04/28 22:44:33 syd Exp $";
  107. X
  108. X/*******************************************************************************
  109. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  110. X *
  111. X *             Copyright (c) 1986, 1987 Dave Taylor
  112. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  113. X *******************************************************************************
  114. X * Bug reports, patches, comments, suggestions should be sent to:
  115. X *
  116. X *    Syd Weinstein, Elm Coordinator
  117. X *    elm@DSI.COM            dsinc!elm
  118. X *
  119. X *******************************************************************************
  120. X * $Log:    arepdaem.c,v $
  121. X * Revision 4.1  90/04/28  22:44:33  syd
  122. X * checkin of Elm 2.3 as of Release PL0
  123. X * 
  124. X *
  125. X ******************************************************************************/
  126. X
  127. X/** Keep track of mail as it arrives, and respond by sending a 'recording'
  128. X    file to the sender as new mail is received.
  129. X
  130. X    Note: the user program that interacts with this program is the
  131. X    'autoreply' program and that should be consulted for further
  132. X    usage information.
  133. X
  134. X    This program is part of the 'autoreply' system, and is designed
  135. X    to run every hour and check all mailboxes listed in the file 
  136. X    "/etc/autoreply.data", where the data is in the form:
  137. X
  138. X    username    replyfile    current-mailfile-size
  139. X
  140. X    To avoid a flood of autoreplies, this program will NOT reply to mail 
  141. X    that contains header "X-Mailer: fastmail".  Further, each time the 
  142. X    program responds to mail, the 'mailfile size' entry is updated in
  143. X    the file /etc/autoreply.data to allow the system to be brought 
  144. X    down and rebooted without any loss of data or duplicate messages.
  145. X
  146. X    This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep,
  147. X    to ensure that more than one copy of itself is never running.  For this
  148. X    reason, it is recommended that this daemon be started up each morning
  149. X    from cron, since it will either start since it's needed or simply see
  150. X    that the file is there and disappear.
  151. X
  152. X    Since this particular program is the main daemon answering any
  153. X    number of different users, it must be run with uid root.
  154. X**/
  155. X
  156. X#include <stdio.h>
  157. X#include "defs.h"
  158. X
  159. X#ifdef BSD
  160. X# include <sys/time.h>
  161. X#else
  162. X# include <time.h>
  163. X#endif
  164. X
  165. X#include <sys/types.h>
  166. X#include <sys/stat.h>
  167. X#include <signal.h>
  168. X#include <fcntl.h>
  169. X#include <errno.h>
  170. X
  171. Xstatic char ident[] = { WHAT_STRING };
  172. X
  173. X#define arep_lock_file    "LCK..arep"
  174. X
  175. X#define autoreply_file    "/etc/autoreply.data"
  176. X
  177. X#define logfile        "/etc/autoreply.log"    /* first choice   */
  178. X#define logfile2    "/tmp/autoreply.log"    /* second choice  */
  179. X
  180. X#define BEGINNING    0        /* see fseek(3S) for info */
  181. X#define SLEEP_TIME    3600        /* run once an hour       */
  182. X#define MAX_PEOPLE    20        /* max number in program  */
  183. X
  184. X#define EXISTS        00        /* lock file exists??     */
  185. X
  186. X#define remove_return(s)    if (strlen(s) > 0) { \
  187. X                      if (s[strlen(s)-1] == '\n') \
  188. X                    s[strlen(s)-1] = '\0'; \
  189. X                        }
  190. X
  191. Xstruct replyrec {
  192. X    char     username[NLEN];        /* login name of user */
  193. X    char    mailfile[SLEN];        /* name of mail file  */
  194. X    char    replyfile[SLEN];    /* name of reply file */
  195. X    long    mailsize;        /* mail file size     */
  196. X    int     in_list;        /* for new replies    */
  197. X      } reply_table[MAX_PEOPLE];
  198. X
  199. XFILE  *logfd;                /* logfile (log action)   */
  200. Xlong  autoreply_size = 0L;        /* size of autoreply file */
  201. Xint   active = 0;            /* # of people 'enrolled' */
  202. X
  203. XFILE  *open_logfile();            /* forward declaration    */
  204. X
  205. Xlong  bytes();                /*       ditto           */
  206. X
  207. X#ifdef VOIDSIG
  208. Xvoid    term_signal();
  209. X#else
  210. Xint    term_signal();
  211. X#endif
  212. X
  213. Xmain()
  214. X{
  215. X    long size;
  216. X    int  person, data_changed;
  217. X
  218. X    if (fork()) exit(0);
  219. X
  220. X    if (! lock())
  221. X      exit(0);    /* already running! */
  222. X
  223. X    signal(SIGTERM, term_signal);     /* Terminate signal         */
  224. X
  225. X/*
  226. X *    note the usage of the BSD style setpgrp wont hurt
  227. X *    system V as its calling sequence is no arguments.
  228. X *    The idea is to disassociate from the terminal to
  229. X *    prevent signals.
  230. X */
  231. X    person = getpid();
  232. X    setpgrp(person, person);
  233. X
  234. X    while (1) {
  235. X
  236. X      logfd = open_logfile();    /* open the log */
  237. X
  238. X      /* 1. check to see if autoreply table has changed.. */
  239. X
  240. X      if ((size = bytes(autoreply_file)) != autoreply_size) {
  241. X        read_autoreply_file(); 
  242. X        autoreply_size = size;
  243. X      }
  244. X
  245. X      /* 2. now for each active person... */
  246. X    
  247. X      data_changed = 0;
  248. X
  249. X      for (person = 0; person < active; person++) {
  250. X        if ((size = bytes(reply_table[person].mailfile)) != 
  251. X        reply_table[person].mailsize) {
  252. X          if (size > reply_table[person].mailsize)
  253. X            read_newmail(person);
  254. X          /* else mail removed - resync */
  255. X          reply_table[person].mailsize = size;
  256. X          data_changed++;
  257. X        }
  258. X      }
  259. X
  260. X      /* 3. if data changed, update autoreply file */
  261. X
  262. X      if (data_changed)
  263. X        update_autoreply_file();
  264. X
  265. X      close_logfile();        /* close the logfile again */
  266. X
  267. X      /* 4. Go to sleep...  */
  268. X
  269. X      sleep(SLEEP_TIME);
  270. X    }
  271. X}
  272. X
  273. Xint
  274. Xread_autoreply_file()
  275. X{
  276. X    /** We're here because the autoreply file has changed size!!  It
  277. X        could either be because someone has been added or because
  278. X        someone has been removed...since the list will always be in
  279. X        order (nice, eh?) we should have a pretty easy time of it...
  280. X    **/
  281. X
  282. X    FILE *file;
  283. X    char username[SLEN],     replyfile[SLEN];
  284. X    int  person;
  285. X     long size;
  286. X    
  287. X    log("Autoreply data file has changed!  Reading...");
  288. X
  289. X/*
  290. X * clear old entries prior to reread
  291. X */
  292. X    for (person = 0; person < active; person++)
  293. X      reply_table[person].in_list = 0;
  294. X
  295. X    if ((file = fopen(autoreply_file,"r")) == NULL) {
  296. X      log("No-one is using autoreply...");
  297. X    } else {
  298. X      while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) {
  299. X        /* check to see if this person is already in the list */
  300. X        if ((person = in_list(username)) != -1) {
  301. X          reply_table[person].in_list = 1;
  302. X          reply_table[person].mailsize = size;     /* sync */
  303. X        }
  304. X        else {     /* if not, add them */
  305. X          if (active == MAX_PEOPLE) {
  306. X        unlock();
  307. X        exit(log("Couldn't add %s - already at max people!", 
  308. X               username));
  309. X          }
  310. X          log("adding %s to the active list", username);
  311. X          strcpy(reply_table[active].username, username);
  312. X          sprintf(reply_table[active].mailfile, "%s%s", mailhome, username);
  313. X          strcpy(reply_table[active].replyfile, replyfile);
  314. X          reply_table[active].mailsize = size;
  315. X          reply_table[active].in_list = 1;    /* obviously! */
  316. X          active++;
  317. X        }
  318. X      }
  319. X      fclose(file);
  320. X    }
  321. X
  322. X    /** now check to see if anyone has been removed... **/
  323. X
  324. X    for (person = 0; person < active; person++)
  325. X      if (reply_table[person].in_list == 0) {
  326. X         log("removing %s from the active list", 
  327. X          reply_table[person].username);
  328. X        strcpy(reply_table[person].username, 
  329. X           reply_table[active-1].username);
  330. X        strcpy(reply_table[person].mailfile, 
  331. X           reply_table[active-1].mailfile);
  332. X        strcpy(reply_table[person].replyfile, 
  333. X           reply_table[active-1].replyfile);
  334. X        reply_table[person].mailsize = reply_table[active-1].mailsize;
  335. X        active--;
  336. X      }
  337. X}
  338. X
  339. Xupdate_autoreply_file()
  340. X{
  341. X    /** update the entries in the autoreply file... **/
  342. X
  343. X    FILE *file;
  344. X    register int person;
  345. X
  346. X    if ((file = fopen(autoreply_file,"w")) == NULL) {
  347. X          log("Couldn't update autoreply file!");
  348. X      return;
  349. X    }
  350. X
  351. X    for (person = 0; person < active; person++)
  352. X      fprintf(file, "%s %s %ld\n",
  353. X          reply_table[person].username,
  354. X          reply_table[person].replyfile,
  355. X          reply_table[person].mailsize);
  356. X
  357. X    fclose(file);
  358. X
  359. X/*    printf("updated autoreply file\n"); */
  360. X    autoreply_size = bytes(autoreply_file);
  361. X}
  362. X
  363. Xint
  364. Xin_list(name)
  365. Xchar *name;
  366. X{
  367. X    /** search the current active reply list for the specified username.
  368. X        return the index if found, or '-1' if not. **/
  369. X
  370. X    register int iindex;
  371. X
  372. X    for (iindex = 0; iindex < active; iindex++)
  373. X      if (strcmp(name, reply_table[iindex].username) == 0)
  374. X        return(iindex);
  375. X    
  376. X    return(-1);
  377. X}
  378. X
  379. Xread_newmail(person)
  380. Xint person;
  381. X{
  382. X    /** Read the new mail for the specified person. **/
  383. X
  384. X    
  385. X    FILE *mailfile;
  386. X    char from_whom[SLEN], subject[SLEN];
  387. X    int  sendit;
  388. X
  389. X    log("New mail for %s", reply_table[person].username);
  390. X
  391. X        if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL)
  392. X           return(log("can't open mailfile for user %s", 
  393. X            reply_table[person].username));
  394. X
  395. X        if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1)
  396. X           return(log("couldn't seek to %ld in mail file!", 
  397. X                   reply_table[person].mailsize));
  398. X
  399. X    while (get_return(mailfile, person, from_whom, subject, &sendit) != -1)
  400. X      if (sendit)
  401. X        reply_to_mail(person, from_whom, subject);
  402. X
  403. X    return;
  404. X}
  405. X
  406. Xint
  407. Xget_return(file, person, from, subject, sendit)
  408. XFILE *file;
  409. Xint  person, *sendit;
  410. Xchar *from, *subject;
  411. X{
  412. X    /** Reads the new message and return the from and subject lines.
  413. X        sendit is set to true iff it isn't a machine generated msg
  414. X    **/
  415. X    
  416. X    char name1[SLEN], name2[SLEN], lastname[SLEN];
  417. X    char buffer[SLEN], hold_return[NLEN];
  418. X    int done = 0, in_header = 0;
  419. X
  420. X    from[0] = '\0';
  421. X    name1[0] = '\0';
  422. X    name2[0] = '\0';
  423. X    lastname[0] = '\0';
  424. X    *sendit = 1;
  425. X
  426. X    while (! done) {
  427. X
  428. X      if (fgets(buffer, SLEN, file) == NULL)
  429. X    return(-1);
  430. X
  431. X      if (first_word(buffer, "From ")) {
  432. X    in_header++;
  433. X    sscanf(buffer, "%*s %s", hold_return);
  434. X      }
  435. X      else if (in_header) {
  436. X        if (first_word(buffer, ">From")) {
  437. X      sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2);
  438. X      add_site(from, name2, lastname);
  439. X        }
  440. X        else if (first_word(buffer,"Subject:")) {
  441. X      remove_return(buffer);
  442. X      strcpy(subject, (char *) (buffer + 8));
  443. X        }
  444. X        else if (first_word(buffer,"X-Mailer: fastmail"))
  445. X      *sendit = 0;
  446. X        else if (strlen(buffer) == 1)
  447. X      done = 1;
  448. X      }
  449. X    }
  450. X
  451. X    if (from[0] == '\0')
  452. X      strcpy(from, hold_return); /* default address! */
  453. X    else
  454. X      add_site(from, name1, lastname);    /* get the user name too! */
  455. X
  456. X    return(0);
  457. X}
  458. X
  459. Xadd_site(buffer, site, lastsite)
  460. Xchar *buffer, *site, *lastsite;
  461. X{
  462. X    /** add site to buffer, unless site is 'uucp', or the same as 
  463. X        lastsite.   If not, set lastsite to site.
  464. X    **/
  465. X
  466. X    char local_buffer[SLEN], *strip_parens();
  467. X
  468. X    if (strcmp(site, "uucp") != 0)
  469. X      if (strcmp(site, lastsite) != 0) {
  470. X          if (buffer[0] == '\0')
  471. X            strcpy(buffer, strip_parens(site));         /* first in list! */
  472. X          else {
  473. X            sprintf(local_buffer,"%s!%s", buffer, strip_parens(site));
  474. X            strcpy(buffer, local_buffer);
  475. X          }
  476. X          strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */
  477. X       }
  478. X}
  479. X
  480. Xremove_first_word(string)
  481. Xchar *string;
  482. X{    /** removes first word of string, ie up to first non-white space
  483. X        following a white space! **/
  484. X
  485. X    register int loc;
  486. X
  487. X    for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  488. X        ;
  489. X
  490. X    while (string[loc] == ' ' || string[loc] == '\t')
  491. X      loc++;
  492. X    
  493. X    move_left(string, loc);
  494. X}
  495. X
  496. Xmove_left(string, chars)
  497. Xchar string[];
  498. Xint  chars;
  499. X{
  500. X    /** moves string chars characters to the left DESTRUCTIVELY **/
  501. X
  502. X    register int i;
  503. X
  504. X    chars--; /* index starting at zero! */
  505. X
  506. X    for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  507. X      string[i-chars] = string[i];
  508. X
  509. X    string[i-chars] = '\0';
  510. X}
  511. X
  512. Xreply_to_mail(person, from, subject)
  513. Xint   person;
  514. Xchar *from, *subject;
  515. X{
  516. X    /** Respond to the message from the specified person with the
  517. X        specified subject... **/
  518. X    
  519. X    char buffer[SLEN];
  520. X
  521. X    if (strlen(subject) == 0)
  522. X      strcpy(subject, "Auto-reply Mail");
  523. X    else if (! first_word(subject,"Auto-reply")) {
  524. X      sprintf(buffer, "Auto-reply to:%s", subject);
  525. X      strcpy(subject, buffer);
  526. X    }
  527. X
  528. X    log("auto-replying to '%s'", from);
  529. X
  530. X    mail(from, subject, reply_table[person].replyfile, person);
  531. X}    
  532. X
  533. Xreverse(string)
  534. Xchar *string;
  535. X{
  536. X    /** reverse string... pretty trivial routine, actually! **/
  537. X
  538. X    char buffer[SLEN];
  539. X    register int i, j = 0;
  540. X
  541. X    for (i = strlen(string)-1; i >= 0; i--)
  542. X      buffer[j++] = string[i];
  543. X
  544. X    buffer[j] = '\0';
  545. X
  546. X    strcpy(string, buffer);
  547. X}
  548. X
  549. Xlong
  550. Xbytes(name)
  551. Xchar *name;
  552. X{
  553. X    /** return the number of bytes in the specified file.  This
  554. X        is to check to see if new mail has arrived....  **/
  555. X
  556. X    int ok = 1;
  557. X    extern int errno;    /* system error number! */
  558. X    struct stat buffer;
  559. X
  560. X    if (stat(name, &buffer) != 0)
  561. X      if (errno != 2) {
  562. X       unlock();
  563. X       exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  564. X      }
  565. X      else
  566. X        ok = 0;
  567. X    
  568. X    return(ok ? buffer.st_size : 0);
  569. X}
  570. X
  571. Xmail(to, subject, filename, person)
  572. Xchar *to, *subject, *filename;
  573. Xint   person;
  574. X{
  575. X    /** Mail 'file' to the user from person... **/
  576. X    
  577. X    char buffer[VERY_LONG_STRING];
  578. X
  579. X    sprintf(buffer, "%s/fastmail -f '%s [autoreply]' -s '%s' %s %s",
  580. X        BIN, reply_table[person].username,
  581. X            subject, filename, to);
  582. X    
  583. X    system(buffer);
  584. X}
  585. X
  586. Xlog(message, arg)
  587. Xchar *message;
  588. Xchar *arg;
  589. X{
  590. X    /** Put log entry into log file.  Use the format:
  591. X          date-time: <message>
  592. X    **/
  593. X
  594. X    struct tm *thetime;
  595. X    long      clock;
  596. X#ifndef    _POSIX_SOURCE
  597. X    struct tm *localtime(); 
  598. X    long      time();
  599. X#endif
  600. X    char      buffer[SLEN];
  601. X
  602. X    /** first off, get the time and date **/
  603. X
  604. X    clock = time((long *) 0);       /* seconds since ???   */
  605. X    thetime = localtime(&clock);    /* and NOW the time... */
  606. X
  607. X    /** then put the message out! **/
  608. X
  609. X    sprintf(buffer, message, arg);
  610. X
  611. X    fprintf(logfd,"%d/%d-%d:%02d: %s\n", 
  612. X        thetime->tm_mon+1, thetime->tm_mday,
  613. X            thetime->tm_hour,  thetime->tm_min,
  614. X            buffer);
  615. X}
  616. X
  617. XFILE *open_logfile()
  618. X{
  619. X    /** open the logfile.  returns a valid file descriptor **/
  620. X
  621. X    FILE *fd;
  622. X
  623. X    if ((fd = fopen(logfile, "a")) == NULL)
  624. X      if ((fd = fopen(logfile2, "a")) == NULL) {
  625. X        unlock();
  626. X        exit(1);    /* give up! */
  627. X      }
  628. X
  629. X    return( (FILE *) fd);
  630. X}
  631. X
  632. Xclose_logfile()
  633. X{
  634. X    /** Close the logfile until needed again. **/
  635. X
  636. X    fclose(logfd);
  637. X}
  638. X
  639. Xchar *strip_parens(string)
  640. Xchar *string;
  641. X{
  642. X    /** Return string with all parenthesized information removed.
  643. X        This is a non-destructive algorithm... **/
  644. X
  645. X    static char  buffer[SLEN];
  646. X    register int depth = 0, buffer_index = 0;
  647. X
  648. X    for (; *string; string++) {
  649. X      if (*string == '(')
  650. X        depth++;
  651. X      else if (*string == ')') 
  652. X        depth--;
  653. X      else if (depth == 0)
  654. X        buffer[buffer_index++] = *string;
  655. X    }
  656. X    
  657. X    buffer[buffer_index] = '\0';
  658. X
  659. X    return( (char *) buffer);
  660. X}
  661. X
  662. X/*** LOCK and UNLOCK - ensure only one copy of this daemon running at any
  663. X     given time by using a file existance semaphore (wonderful stuff!) ***/
  664. X
  665. Xlock()
  666. X{
  667. X    char lock_name[SLEN];        /* name of lock file  */
  668. X    char pid_buffer[SHORT];
  669. X    int pid, create_fd;
  670. X    extern int errno;    /* system error number! */
  671. X
  672. X    sprintf(lock_name, "%s/%s", LOCK_DIR, arep_lock_file);
  673. X#ifdef PIDCHECK
  674. X      /** first, try to read the lock file, and if possible, check the pid.
  675. X      If we can validate that the pid is no longer active, then remove
  676. X      the lock file.
  677. X       **/
  678. X    if((create_fd=open(lock_name,O_RDONLY)) != -1) {
  679. X      if (read(create_fd, pid_buffer, SHORT) > 0) {
  680. X        pid = atoi(pid_buffer);
  681. X        if (pid) {
  682. X          if (kill(pid, 0)) {
  683. X            close(create_fd);
  684. X            if (unlink(lock_name) != 0) {
  685. X            printf("Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
  686. X            error_name(errno), error_description(errno), lock_name, "lock");
  687. X            return(0);
  688. X            }
  689. X          } else /* kill pid check succeeded */
  690. X            return(0);
  691. X        } else /* pid was zero */
  692. X          return(0);
  693. X      } else /* read failed */
  694. X        return(0);
  695. X    }
  696. X    /* ok, either the open failed or we unlinked it, now recreate it. */
  697. X#else
  698. X    if (access(lock_name, EXISTS) == 0)
  699. X      return(0);    /* file already exists */
  700. X#endif
  701. X
  702. X    if (create_fd=creat(lock_name, O_RDONLY) == -1)
  703. X      return(0);    /* can't create file!!   */
  704. X
  705. X    sprintf(pid_buffer,"%d\n", getpid() );        /* write the current pid to the file */
  706. X    write(create_fd, pid_buffer, strlen(pid_buffer));
  707. X    close(create_fd);                /* no need to keep it open */
  708. X    
  709. X    return(1);
  710. X
  711. X}
  712. X
  713. Xunlock()
  714. X{
  715. X    /** remove lock file if it's there! **/
  716. X
  717. X    (void) unlink(arep_lock_file);
  718. X}
  719. X
  720. X#ifdef VOIDSIG
  721. Xvoid    term_signal()
  722. X#else
  723. Xint    term_signal()
  724. X#endif
  725. X{
  726. X    unlock();
  727. X    exit(1);    /* give up! */
  728. X}
  729. SHAR_EOF
  730. chmod 0444 utils/arepdaem.c || echo "restore of utils/arepdaem.c fails"
  731. echo "x - extracting utils/autoreply.c (Text)"
  732. sed 's/^X//' << 'SHAR_EOF' > utils/autoreply.c &&
  733. X
  734. Xstatic char rcsid[] = "@(#)$Id: autoreply.c,v 4.1 90/04/28 22:44:35 syd Exp $";
  735. X
  736. X/*******************************************************************************
  737. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  738. X *
  739. X *             Copyright (c) 1986, 1987 Dave Taylor
  740. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  741. X *******************************************************************************
  742. X * Bug reports, patches, comments, suggestions should be sent to:
  743. X *
  744. X *    Syd Weinstein, Elm Coordinator
  745. X *    elm@DSI.COM            dsinc!elm
  746. X *
  747. X *******************************************************************************
  748. X * $Log:    autoreply.c,v $
  749. X * Revision 4.1  90/04/28  22:44:35  syd
  750. X * checkin of Elm 2.3 as of Release PL0
  751. X * 
  752. X *
  753. X ******************************************************************************/
  754. X
  755. X/** This is the front-end for the autoreply system, and performs two 
  756. X    functions: it either adds the user to the list of people using the
  757. X    autoreply function (starting the daemon if no-one else) or removes
  758. X    a user from the list of people.
  759. X
  760. X    Usage:  autoreply filename
  761. X        autoreply "off"
  762. X    or  autoreply        [to find current status]
  763. X    
  764. X**/
  765. X
  766. X#include <stdio.h>
  767. X#include <errno.h>
  768. X#include <sys/types.h>
  769. X#include <sys/stat.h>
  770. X
  771. X#ifdef PWDINSYS
  772. X#  include <sys/pwd.h>
  773. X#else
  774. X#  include <pwd.h>
  775. X#endif
  776. X
  777. X#include "defs.h"
  778. X
  779. Xstatic char ident[] = { WHAT_STRING };
  780. X
  781. X#define  tempdir    "/tmp/arep"        /* file prefix          */
  782. X#define  autoreply_file    "/etc/autoreply.data"   /* autoreply data file  */
  783. X
  784. Xextern   int errno;                /* system error code    */
  785. Xchar     username[NLEN];            /* login name of user   */
  786. X
  787. Xmain(argc, argv)
  788. Xint    argc;
  789. Xchar *argv[];
  790. X{
  791. X    char filename[SLEN];
  792. X    int userid;
  793. X    struct passwd *pass;
  794. X#ifndef    _POSIX_SOURCE
  795. X    struct passwd *getpwuid();
  796. X#endif
  797. X
  798. X    if (argc > 2) {
  799. X      printf("Usage: %s <filename>\tto start autoreply,\n", argv[0]);
  800. X      printf("       %s off\t\tto turn off autoreply\n", argv[0]);
  801. X      printf("   or  %s    \t\tto check current status\n", argv[0]);
  802. X      exit(1);
  803. X    }
  804. X
  805. X    userid  = getuid();
  806. X
  807. X    /*
  808. X     * Get username (logname) field from the password entry for this user id.
  809. X     */
  810. X
  811. X    if((pass = getpwuid(userid)) == NULL) {
  812. X      printf("You have no password entry!");
  813. X      exit(1);
  814. X    }
  815. X    strcpy(username, pass->pw_name);
  816. X
  817. X    if (argc == 1 || strcmp(argv[1], "off") == 0) 
  818. X      remove_user((argc == 1));
  819. X    else {
  820. X      strcpy(filename, argv[1]);
  821. X      if (access(filename,READ_ACCESS) != 0) {
  822. X        printf("Error: Can't read file '%s'\n", filename);
  823. X        exit(1);
  824. X      }
  825. X      
  826. X      if (filename[0] != '/') /* prefix home directory */
  827. X        sprintf(filename,"%s/%s", getenv("HOME"), argv[1]);
  828. X
  829. X      add_user(filename);
  830. X    }
  831. X
  832. X    exit(0);
  833. X}
  834. X
  835. Xremove_user(stat_only)
  836. Xint stat_only;
  837. X{
  838. X    /** Remove the user from the list of currently active autoreply 
  839. X        people.  If 'stat_only' is set, then just list the name of
  840. X        the file being used to autoreply with, if any. **/
  841. X
  842. X    FILE *temp, *repfile;
  843. X    char  tempfile[SLEN], user[SLEN], filename[SLEN];
  844. X    int   c, copied = 0, found = 0;
  845. X    long  filesize, bytes();
  846. X
  847. X    if (! stat_only) {
  848. X      sprintf(tempfile, "%s.%06d", tempdir, getpid());
  849. X
  850. X      if ((temp = fopen(tempfile, "w")) == NULL) {
  851. X        printf("Error: couldn't open tempfile '%s'.  Not removed\n",
  852. X            tempfile);
  853. X        exit(1);
  854. X      }
  855. X    }
  856. X
  857. X    if ((repfile = fopen(autoreply_file, "r")) == NULL) {
  858. X      if (stat_only) {
  859. X        printf("You're not currently autoreplying to mail.\n");
  860. X        exit(0);
  861. X      }
  862. X      printf("No-one is autoreplying to their mail!\n");
  863. X      exit(0);
  864. X    }
  865. X
  866. X    /** copy out of real replyfile... **/
  867. X
  868. X    while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) 
  869. X
  870. X      if (strcmp(user, username) != 0) {
  871. X        if (! stat_only) {
  872. X          copied++;
  873. X          fprintf(temp, "%s %s %ld\n", user, filename, filesize);
  874. X        }
  875. X      }
  876. X      else {
  877. X        if (stat_only) {
  878. X          printf("You're currently autoreplying to mail with the file %s\n",              filename); 
  879. X          exit(0);
  880. X        }
  881. X        found++;
  882. X      }
  883. X
  884. X    fclose(temp);
  885. X    fclose(repfile);
  886. X
  887. X    if (! found) {
  888. X      printf("You're not currently autoreplying to mail%s\n",
  889. X          stat_only? "." : "!");
  890. X      if (! stat_only)
  891. X        unlink(tempfile);
  892. X      exit(! stat_only);
  893. X    }
  894. X
  895. X    /** now copy tempfile back into replyfile **/
  896. X
  897. X    if (copied == 0) {    /* removed the only person! */
  898. X      unlink(autoreply_file);
  899. X    }
  900. X    else {            /* save everyone else   */
  901. X      
  902. X      if ((temp = fopen(tempfile,"r")) == NULL) {
  903. X        printf("Error: couldn't reopen tempfile '%s'.  Not removed.\n",
  904. X            tempfile);
  905. X        unlink(tempfile);
  906. X        exit(1);
  907. X      }
  908. X
  909. X      if ((repfile = fopen(autoreply_file, "w")) == NULL) {
  910. X        printf(
  911. X          "Error: couldn't reopen autoreply file for writing!  Not removed.\n");
  912. X        unlink(tempfile);
  913. X        exit(1);
  914. X      }
  915. X
  916. X      while ((c = getc(temp)) != EOF)
  917. X        putc(c, repfile);
  918. X
  919. X      fclose(temp);
  920. X      fclose(repfile);
  921. X    
  922. X    }
  923. X    unlink(tempfile);
  924. X
  925. X    if (found > 1)
  926. X      printf("Warning: your username appeared %d times!!   Removed all\n", 
  927. X          found);
  928. X    else
  929. X      printf("You've been removed from the autoreply table.\n");
  930. X}
  931. X
  932. Xadd_user(filename)
  933. Xchar *filename;
  934. X{
  935. X    /** add the user to the autoreply file... **/
  936. X
  937. X    FILE *repfile;
  938. X    char  mailfile[SLEN];
  939. X    long  bytes();
  940. X
  941. X    if ((repfile = fopen(autoreply_file, "a")) == NULL) {
  942. X      printf("Error: couldn't open the autoreply file!  Not added\n");
  943. X      exit(1);
  944. X    }
  945. X    
  946. X    sprintf(mailfile,"%s/%s", mailhome, username);
  947. X
  948. X    fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile));
  949. X
  950. X    fclose(repfile);
  951. X
  952. X    printf("You've been added to the autoreply system.\n");
  953. X}
  954. X
  955. X
  956. Xlong
  957. Xbytes(name)
  958. Xchar *name;
  959. X{
  960. X    /** return the number of bytes in the specified file.  This
  961. X        is to check to see if new mail has arrived....  **/
  962. X
  963. X    int ok = 1;
  964. X    extern int errno;    /* system error number! */
  965. X    struct stat buffer;
  966. X
  967. X    if (stat(name, &buffer) != 0)
  968. X      if (errno != 2)
  969. X       exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name));
  970. X      else
  971. X        ok = 0;
  972. X    
  973. X    return(ok ? buffer.st_size : 0L);
  974. X}
  975. SHAR_EOF
  976. chmod 0444 utils/autoreply.c || echo "restore of utils/autoreply.c fails"
  977. echo "x - extracting utils/checkalias (Text)"
  978. sed 's/^X//' << 'SHAR_EOF' > utils/checkalias &&
  979. X: Use /bin/sh
  980. X# checkalias: part of the Elm mail system
  981. X# @(#)$Id: checkalias,v 4.1 90/04/28 22:44:36 syd Exp $
  982. Xif [ "$*" = "" ]; then
  983. X  echo Usage: checkalias alias \[alias ...\] 1>&2
  984. X  exit 1
  985. Xfi
  986. Xexec elm -c $*
  987. SHAR_EOF
  988. chmod 0444 utils/checkalias || echo "restore of utils/checkalias fails"
  989. echo "x - extracting utils/expand.c (Text)"
  990. sed 's/^X//' << 'SHAR_EOF' > utils/expand.c &&
  991. X
  992. Xstatic char rcsid[] = "@(#)$Id: expand.c,v 4.1 90/04/28 22:44:37 syd Exp $";
  993. X
  994. X/*******************************************************************************
  995. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  996. X *
  997. X *             Copyright (c) 1986, 1987 Dave Taylor
  998. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  999. X *******************************************************************************
  1000. X * Bug reports, patches, comments, suggestions should be sent to:
  1001. X *
  1002. X *    Syd Weinstein, Elm Coordinator
  1003. X *    elm@DSI.COM            dsinc!elm
  1004. X *
  1005. X *******************************************************************************
  1006. X * $Log:    expand.c,v $
  1007. X * Revision 4.1  90/04/28  22:44:37  syd
  1008. X * checkin of Elm 2.3 as of Release PL0
  1009. X * 
  1010. X *
  1011. X ******************************************************************************/
  1012. X
  1013. X/** This is a library routine for the various utilities that allows
  1014. X    users to have the standard 'Elm' folder directory nomenclature
  1015. X    for all filenames (e.g. '+', '=' or '%').  It should be compiled
  1016. X    and then linked in as needed.
  1017. X
  1018. X**/
  1019. X
  1020. X#include <stdio.h>
  1021. X#include "defs.h"
  1022. X
  1023. Xchar *expand_define();
  1024. X
  1025. Xint
  1026. Xexpand(filename)
  1027. Xchar *filename;
  1028. X{
  1029. X    /** Expand the filename since the first character is a meta-
  1030. X        character that should expand to the "maildir" variable
  1031. X        in the users ".elmrc" file...
  1032. X
  1033. X        Note: this is a brute force way of getting the entry out 
  1034. X        of the .elmrc file, and isn't recommended for the faint 
  1035. X        of heart!
  1036. X    **/
  1037. X
  1038. X    FILE *rcfile;
  1039. X    char  buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr;
  1040. X    int   foundit = 0;
  1041. X
  1042. X    bufptr = (char *) buffer;        /* same address */
  1043. X    
  1044. X    if ((home = getenv("HOME")) == NULL) {
  1045. X      printf(
  1046. X         "Can't expand environment variable $HOME to find .elmrc file!\n");
  1047. X      return(NO);
  1048. X    }
  1049. X
  1050. X    sprintf(buffer, "%s/%s", home, elmrcfile);
  1051. X
  1052. X    if ((rcfile = fopen(buffer, "r")) == NULL) {
  1053. X      printf("Can't open your \".elmrc\" file (%s) for reading!\n",
  1054. X         buffer);
  1055. X      return(NO);
  1056. X    }
  1057. X
  1058. X    while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) {
  1059. X      if (strncmp(buffer, "maildir", 7) == 0 ||
  1060. X          strncmp(buffer, "folders", 7) == 0) {
  1061. X        while (*bufptr != '=' && *bufptr) 
  1062. X          bufptr++;
  1063. X        bufptr++;            /* skip the equals sign */
  1064. X        while (whitespace(*bufptr) && *bufptr)
  1065. X          bufptr++; 
  1066. X        home = bufptr;        /* remember this address */
  1067. X
  1068. X        while (! whitespace(*bufptr) && *bufptr != '\n')
  1069. X          bufptr++;
  1070. X
  1071. X        *bufptr = '\0';        /* remove trailing space */
  1072. X        foundit++;
  1073. X      }
  1074. X    }
  1075. X
  1076. X    fclose(rcfile);            /* be nice... */
  1077. X
  1078. X    if (! foundit) {
  1079. X      printf("Couldn't find \"maildir\" in your .elmrc file!\n");
  1080. X      return(NO);
  1081. X    }
  1082. X
  1083. X    /** Home now points to the string containing your maildir, with
  1084. X        no leading or trailing white space...
  1085. X    **/
  1086. X
  1087. X    if ((expanded_dir = expand_define(home)) == NULL)
  1088. X        return(NO);
  1089. X
  1090. X    sprintf(buffer, "%s%s%s", expanded_dir, 
  1091. X        (expanded_dir[strlen(expanded_dir)-1] == '/' ||
  1092. X        filename[0] == '/') ? "" : "/", (char *) filename+1);
  1093. X
  1094. X    strcpy(filename, buffer);
  1095. X    return(YES);
  1096. X}
  1097. X
  1098. Xchar *expand_define(maildir)
  1099. Xchar *maildir;
  1100. X{
  1101. X    /** This routine expands any occurances of "~" or "$var" in
  1102. X        the users definition of their maildir directory out of
  1103. X        their .elmrc file.
  1104. X
  1105. X        Again, another routine not for the weak of heart or staunch
  1106. X        of will!
  1107. X    **/
  1108. X
  1109. X    static char buffer[SLEN];    /* static buffer AIEE!! */
  1110. X    char   name[SLEN],        /* dynamic buffer!! (?) */
  1111. X           *nameptr,           /*  pointer to name??     */
  1112. X           *value;              /* char pointer for munging */
  1113. X
  1114. X    if (*maildir == '~') 
  1115. X      sprintf(buffer, "%s%s", getenv("HOME"), ++maildir);
  1116. X    else if (*maildir == '$') {     /* shell variable */
  1117. X
  1118. X      /** break it into a single word - the variable name **/
  1119. X
  1120. X      strcpy(name, (char *) maildir + 1);    /* hurl the '$' */
  1121. X      nameptr = (char *) name;
  1122. X      while (*nameptr != '/' && *nameptr) nameptr++;
  1123. X      *nameptr = '\0';    /* null terminate */
  1124. X      
  1125. X      /** got word "name" for expansion **/
  1126. X
  1127. X      if ((value = getenv(name)) == NULL) {
  1128. X        printf("Couldn't expand shell variable $%s in .elmrc!\n", name);
  1129. X        return(NULL);
  1130. X      }
  1131. X      sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1);
  1132. X    }
  1133. X    else strcpy(buffer, maildir);
  1134. X
  1135. X    return( ( char *) buffer);
  1136. X}
  1137. SHAR_EOF
  1138. chmod 0444 utils/expand.c || echo "restore of utils/expand.c fails"
  1139. echo "x - extracting utils/fastmail.c (Text)"
  1140. sed 's/^X//' << 'SHAR_EOF' > utils/fastmail.c &&
  1141. X
  1142. Xstatic char rcsid[] = "@(#)$Id: fastmail.c,v 4.1 90/04/28 22:44:39 syd Exp $";
  1143. X
  1144. X/*******************************************************************************
  1145. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1146. X *
  1147. X *             Copyright (c) 1986, 1987 Dave Taylor
  1148. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1149. X *******************************************************************************
  1150. X * Bug reports, patches, comments, suggestions should be sent to:
  1151. X *
  1152. X *    Syd Weinstein, Elm Coordinator
  1153. X *    elm@DSI.COM            dsinc!elm
  1154. X *
  1155. X *******************************************************************************
  1156. X * $Log:    fastmail.c,v $
  1157. X * Revision 4.1  90/04/28  22:44:39  syd
  1158. X * checkin of Elm 2.3 as of Release PL0
  1159. X * 
  1160. X *
  1161. X ******************************************************************************/
  1162. X
  1163. X/** This program is specifically written for group mailing lists and
  1164. X    such batch type mail processing.  It does NOT use aliases at all,
  1165. X    it does NOT read the /etc/password file to find the From: name
  1166. X    of the user and does NOT expand any addresses.  It is meant 
  1167. X    purely as a front-end for either /bin/mail or /usr/lib/sendmail
  1168. X    (according to what is available on the current system).
  1169. X
  1170. X         **** This program should be used with CAUTION *****
  1171. X
  1172. X**/
  1173. X
  1174. X/** The calling sequence for this program is:
  1175. X
  1176. X    fastmail {args}  filename full-email-address 
  1177. X
  1178. X   where args could be any (or all) of;
  1179. X
  1180. X       -b bcc-list        (Blind carbon copies to)
  1181. X       -c cc-list        (carbon copies to)
  1182. X       -d            (debug on)
  1183. X       -f from         (from name)
  1184. X       -F from-addr        (the actual address to be put in the From: line)
  1185. X       -r reply-to-address     (Reply-To:)
  1186. X       -s subject         (subject of message)
  1187. X**/
  1188. X
  1189. X#include <stdio.h>
  1190. X#include "defs.h"
  1191. X#include "patchlevel.h"
  1192. X
  1193. X#ifdef I_TIME
  1194. X#  include <time.h>
  1195. X#endif
  1196. X#ifdef I_SYSTIME
  1197. X#  include <sys/time.h>
  1198. X#endif
  1199. X#ifdef BSD
  1200. X#  include <sys/types.h>
  1201. X#  include <sys/timeb.h>
  1202. X#endif
  1203. X
  1204. Xstatic char ident[] = { WHAT_STRING };
  1205. X
  1206. X#define  binrmail    "/bin/rmail"
  1207. X#define  temphome    "/tmp/fastmail."
  1208. X
  1209. X
  1210. Xchar *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
  1211. X          "Fri", "Sat", "" };
  1212. X
  1213. Xchar *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1214. X          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
  1215. X
  1216. Xchar *get_arpa_date();
  1217. X
  1218. X#if defined(BSD) && !defined(_POSIX_SOURCE)
  1219. X  char *timezone();
  1220. X#else
  1221. X  extern char *tzname[];
  1222. X#endif
  1223. X
  1224. Xmain(argc, argv)
  1225. Xint argc;
  1226. Xchar *argv[];
  1227. X{
  1228. X
  1229. X    extern char *optarg;
  1230. X    extern int optind;
  1231. X    FILE *tempfile;
  1232. X    char hostname[NLEN], username[NLEN], from_string[SLEN], subject[SLEN];
  1233. X    char filename[SLEN], tempfilename[SLEN], command_buffer[256];
  1234. X    char replyto[SLEN], cc_list[SLEN], bcc_list[SLEN], to_list[SLEN];
  1235. X    char from_addr[SLEN];
  1236. X    int  c, sendmail_available, debug = 0;
  1237. X
  1238. X    from_string[0] = '\0';
  1239. X    subject[0] = '\0';
  1240. X    replyto[0] = '\0';
  1241. X    cc_list[0] = '\0';
  1242. X    bcc_list[0] = '\0';
  1243. X    to_list[0] = '\0';
  1244. X    from_addr[0] = '\0';
  1245. X
  1246. X    while ((c = getopt(argc, argv, "b:c:df:F:r:s:")) != EOF) {
  1247. X      switch (c) {
  1248. X        case 'b' : strcpy(bcc_list, optarg);        break;
  1249. X        case 'c' : strcpy(cc_list, optarg);        break;
  1250. X        case 'd' : debug++;                    break;    
  1251. X        case 'f' : strcpy(from_string, optarg);    break;
  1252. X        case 'F' : strcpy(from_addr, optarg);        break;
  1253. X        case 'r' : strcpy(replyto, optarg);        break;
  1254. X        case 's' : strcpy(subject, optarg);        break;
  1255. X        case '?' :
  1256. X          fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
  1257. X          fprintf(stderr, "   where {args} can be;\n");
  1258. X          fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n");
  1259. X          fprintf(stderr,"\t-f from-name\n\t-F from-addr\n");
  1260. X          fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
  1261. X          exit(1);
  1262. X       }
  1263. X    }    
  1264. X
  1265. X    if (optind > argc) {
  1266. X      fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
  1267. X      fprintf(stderr, "   where {args} can be;\n");
  1268. X      fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
  1269. X      fprintf(stderr,"\t-F from-addr\n");
  1270. X      fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n");
  1271. X      exit(1);
  1272. X    }
  1273. X
  1274. X    strcpy(filename, argv[optind++]);
  1275. X
  1276. X    if (optind > argc) {
  1277. X      fprintf(stderr,"Usage: fastmail {args} filename address(es)\n");
  1278. X      fprintf(stderr, "   where {args} can be;\n");
  1279. X      fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n");
  1280. X      fprintf(stderr,"\t-F from-addr\n");
  1281. X      fprintf(stderr,"\t-r reply-to\n\t-s subject\n\n");
  1282. X      exit(1);
  1283. X    }
  1284. X
  1285. X#ifdef HOSTCOMPILED
  1286. X    strncpy(hostname, HOSTNAME, sizeof(hostname));
  1287. X#else
  1288. X    gethostname(hostname, sizeof(hostname));
  1289. X#endif
  1290. X
  1291. X    strcpy(username, getlogin());
  1292. X
  1293. X    if (strlen(username) == 0)
  1294. X      cuserid(username);
  1295. X
  1296. X    if (access(filename, READ_ACCESS) == -1) {
  1297. X      fprintf(stderr, "Error: can't find file %s!\n", filename);
  1298. X      exit(1);
  1299. X    }
  1300. X
  1301. X    sprintf(tempfilename, "%s%d", temphome, getpid());
  1302. X
  1303. X    if ((tempfile = fopen(tempfilename, "w")) == NULL) {
  1304. X      fprintf(stderr, "Couldn't open temp file %s\n", tempfilename);
  1305. X      exit(1);
  1306. X    }
  1307. X
  1308. X    /** Subject must appear even if "null" and must be first
  1309. X        at top of headers for mail because the
  1310. X        pure System V.3 mailer, in its infinite wisdom, now
  1311. X        assumes that anything the user sends is part of the 
  1312. X        message body unless either:
  1313. X        1. the "-s" flag is used (although it doesn't seem
  1314. X           to be supported on all implementations??)
  1315. X        2. the first line is "Subject:".  If so, then it'll
  1316. X           read until a blank line and assume all are meant
  1317. X           to be headers.
  1318. X        So the gory solution here is to move the Subject: line
  1319. X        up to the top.  I assume it won't break anyone elses program
  1320. X        or anything anyway (besides, RFC-822 specifies that the *order*
  1321. X        of headers is irrelevant).  Gahhhhh....
  1322. X    **/
  1323. X    fprintf(tempfile, "Subject: %s\n", subject);
  1324. X
  1325. X    if (strlen(from_string) > 0)
  1326. X      if (strlen(from_addr) > 0)
  1327. X          fprintf(tempfile, "From: %s (%s)\n", from_addr, from_string);
  1328. X      else
  1329. X          fprintf(tempfile, "From: %s!%s (%s)\n", hostname, username, 
  1330. X              from_string);
  1331. X    else
  1332. X      if (strlen(from_addr) > 0)
  1333. X        fprintf(tempfile, "From: %s\n", from_addr);
  1334. X      else
  1335. X        fprintf(tempfile, "From: %s!%s\n", hostname, username);
  1336. X
  1337. X    fprintf(tempfile, "Date: %s\n", get_arpa_date());
  1338. X
  1339. X    if (strlen(replyto) > 0)
  1340. X      fprintf(tempfile, "Reply-To: %s\n", replyto);
  1341. X
  1342. X    while (optind < argc) 
  1343. X          sprintf(to_list, "%s%s%s", to_list, (strlen(to_list) > 0? " ":""), 
  1344. X          argv[optind++]);
  1345. X    
  1346. X    fprintf(tempfile, "To: %s\n", to_list);
  1347. X
  1348. X    if (strlen(cc_list) > 0)
  1349. X      fprintf(tempfile, "Cc: %s\n", cc_list);
  1350. X
  1351. X    fprintf(tempfile, "X-Mailer: fastmail [version %s PL%d]\n",
  1352. X      VERSION, PATCHLEVEL);
  1353. X    fprintf(tempfile, "\n");
  1354. X
  1355. X    fclose(tempfile);
  1356. X
  1357. X    /** now we'll cat both files to /bin/rmail or sendmail... **/
  1358. X
  1359. X    sendmail_available = (access(sendmail, EXECUTE_ACCESS) != -1);
  1360. X
  1361. X    if (debug)
  1362. X        printf("Mailing to %s%s%s%s%s [via %s]\n", to_list,
  1363. X            (strlen(cc_list) > 0 ? " ":""), cc_list,
  1364. X            (strlen(bcc_list) > 0 ? " ":""), bcc_list,
  1365. X            sendmail_available? "sendmail" : "rmail");
  1366. X
  1367. X    sprintf(command_buffer, "cat %s %s | %s %s %s %s", 
  1368. X        tempfilename, filename, 
  1369. X            sendmail_available? sendmail : mailer,
  1370. X        to_list, cc_list, bcc_list);
  1371. X
  1372. X    if (debug)
  1373. X      printf("%s\n", command_buffer);
  1374. X
  1375. X    c = system(command_buffer);
  1376. X
  1377. X    unlink(tempfilename);
  1378. X
  1379. X    exit(c != 0);
  1380. X}
  1381. X
  1382. X
  1383. Xchar *get_arpa_date()
  1384. X{
  1385. X    /** returns an ARPA standard date.  The format for the date
  1386. X        according to DARPA document RFC-822 is exemplified by;
  1387. X
  1388. X                     Mon, 12 Aug 85 6:29:08 MST
  1389. X
  1390. X    **/
  1391. X
  1392. X    static char buffer[SLEN];    /* static character buffer       */
  1393. X    struct tm *the_time;        /* Time structure, see CTIME(3C) */
  1394. X    long       junk;        /* time in seconds....         */
  1395. X#ifndef    _POSIX_SOURCE
  1396. X    struct tm *localtime();
  1397. X#endif
  1398. X#ifdef BSD
  1399. X#  ifndef TZ_MINUTESWEST
  1400. X    struct timeb loc_time;    /* of course this is different! */
  1401. X#    ifndef _POSIX_SOURCE
  1402. X    long time();
  1403. X#    endif
  1404. X#  else
  1405. X    struct  timeval  time_val;        
  1406. X    struct  timezone time_zone;
  1407. X#  endif
  1408. X#else
  1409. X    long time();
  1410. X#endif
  1411. X
  1412. X#ifdef BSD
  1413. X#  ifndef TZ_MINUTESWEST
  1414. X    junk = (long) time((long *) 0);
  1415. X    ftime(&loc_time);
  1416. X#  else
  1417. X    gettimeofday(&time_val, &time_zone);
  1418. X    junk = time_val.tv_sec;
  1419. X#  endif
  1420. X#else
  1421. X    junk = time(0);    /* this must be here for it to work! */
  1422. X#endif
  1423. X    the_time = localtime(&junk);
  1424. X
  1425. X    sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s",
  1426. X      arpa_dayname[the_time->tm_wday],
  1427. X      the_time->tm_mday % 32,
  1428. X      arpa_monname[the_time->tm_mon],
  1429. X      the_time->tm_year % 100,
  1430. X      the_time->tm_hour % 24,
  1431. X      the_time->tm_min  % 61,
  1432. X      the_time->tm_sec  % 61,
  1433. X#if defined(BSD) && !defined(_POSIX_SOURCE)
  1434. X#  ifndef TZ_MINUTESWEST
  1435. X      timezone(loc_time.time_zone, the_time->tz_isdst));
  1436. X#  else
  1437. X#   ifdef GOULD_NP1
  1438. X      the_time->tm_zone);
  1439. X#   else
  1440. X      timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime));
  1441. X#   endif
  1442. X#  endif
  1443. X#else
  1444. X      tzname[the_time->tm_isdst]);
  1445. X#endif
  1446. X    
  1447. X    return( (char *) buffer);
  1448. X}
  1449. SHAR_EOF
  1450. chmod 0444 utils/fastmail.c || echo "restore of utils/fastmail.c fails"
  1451. echo "x - extracting utils/from.c (Text)"
  1452. sed 's/^X//' << 'SHAR_EOF' > utils/from.c &&
  1453. X
  1454. Xstatic char rcsid[] = "@(#)$Id: from.c,v 4.1 90/04/28 22:44:41 syd Exp $";
  1455. X
  1456. X/*******************************************************************************
  1457. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1458. X *
  1459. X *             Copyright (c) 1986, 1987 Dave Taylor
  1460. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1461. X *******************************************************************************
  1462. X * Bug reports, patches, comments, suggestions should be sent to:
  1463. X *
  1464. X *    Syd Weinstein, Elm Coordinator
  1465. X *    elm@DSI.COM            dsinc!elm
  1466. X *
  1467. X *******************************************************************************
  1468. X * $Log:    from.c,v $
  1469. X * Revision 4.1  90/04/28  22:44:41  syd
  1470. X * checkin of Elm 2.3 as of Release PL0
  1471. X * 
  1472. X *
  1473. X ******************************************************************************/
  1474. X
  1475. X/** print out whom each message is from in the pending folder or specified 
  1476. X    one, including a subject line if available.. 
  1477. X
  1478. X**/
  1479. X
  1480. X#include <stdio.h>
  1481. X#include <pwd.h>
  1482. X#include "defs.h"
  1483. X
  1484. Xstatic char ident[] = { WHAT_STRING };
  1485. X
  1486. X#ifdef MMDF
  1487. Xchar username[SLEN] = {0};
  1488. X#endif /* MMDF */
  1489. X
  1490. X#define LINEFEED    (char) 10
  1491. X
  1492. X#define metachar(c)    (c == '=' || c == '+' || c == '%')
  1493. X
  1494. XFILE *mailfile;
  1495. X
  1496. Xint   number = 0,    /* should we number the messages?? */
  1497. X      verbose = 0;    /* and should we prepend a header? */
  1498. X
  1499. Xmain(argc, argv)
  1500. Xint argc;
  1501. Xchar *argv[];
  1502. X{
  1503. X    char infile[SLEN], *cp ;
  1504. X    int  multiple_files = 0, output_files = 0, c;
  1505. X    struct passwd *pass;
  1506. X#ifndef    _POSIX_SOURCE
  1507. X    struct passwd *getpwuid();
  1508. X#endif
  1509. X    extern int optind;
  1510. X
  1511. X    while ((c = getopt(argc, argv, "nv")) != EOF) 
  1512. X      switch (c) {
  1513. X        case (int)'n': number++;        break;
  1514. X        case (int)'v': verbose++;    break;
  1515. X        case (int)'?': printf("Usage: %s [-n] [-v] {filename | username}\n",
  1516. X                 argv[0]);
  1517. X                       exit(1);
  1518. X      }
  1519. X
  1520. X    infile[0] = '\0';
  1521. X    if (optind == argc) {
  1522. X    /*
  1523. X     *    determine mail file from environment variable if found,
  1524. X     *    else use password entry
  1525. X     */
  1526. X      if ((cp = getenv("MAIL")) == NULL) {
  1527. X        if((pass = getpwuid(getuid())) == NULL) {
  1528. X          printf("You have no password entry!");
  1529. X          exit(1);
  1530. X        }
  1531. X        sprintf(infile,"%s%s",mailhome, pass->pw_name);
  1532. X      }
  1533. X      else
  1534. X        strcpy(infile, cp);
  1535. X      optind -= 1;    /* ensure one pass through loop */
  1536. X    }
  1537. X
  1538. X#ifdef MMDF
  1539. X    if((pass = getpwuid(getuid())) == NULL) {
  1540. X      printf("You have no password entry!");
  1541. X      exit(1);
  1542. X    }
  1543. X    strcpy(username,pass->pw_name);
  1544. X#endif /* MMDF */
  1545. X
  1546. X    multiple_files = (argc - optind > 1);
  1547. X
  1548. X    while (optind < argc) {
  1549. X    
  1550. X      if (multiple_files) {
  1551. X        strcpy(infile, argv[optind]);
  1552. X        printf("%s%s: \n", output_files++ > 0 ? "\n":"", infile);
  1553. X      }
  1554. X      else if (infile[0] == '\0')
  1555. X        strcpy(infile, argv[optind]);
  1556. X
  1557. X      if (metachar(infile[0])) {
  1558. X        if (expand(infile) == 0) {
  1559. X           fprintf(stderr, "%s: couldn't expand filename %s!\n", 
  1560. X               argv[0], infile);
  1561. X           exit(1);
  1562. X        }
  1563. X      }
  1564. X
  1565. X      if ((mailfile = fopen(infile,"r")) == NULL) {
  1566. X        if (optind+1 == argc)
  1567. X          printf("No mail.\n");
  1568. X        else {
  1569. X          if (infile[0] == '/') 
  1570. X            printf("Couldn't open folder \"%s\".\n", infile);
  1571. X          else {
  1572. X            sprintf(infile,"%s%s", mailhome, argv[optind]);
  1573. X            if ((mailfile = fopen(infile,"r")) == NULL)
  1574. X              printf("Couldn't open folders \"%s\" or \"%s\".\n",
  1575. X             argv[optind], infile);
  1576. X            else {
  1577. X          if (read_headers()==0)
  1578. X                printf("No messages in that folder!\n");
  1579. X              fclose(mailfile);
  1580. X        }
  1581. X          }
  1582. X        }
  1583. X      } else {
  1584. X        if (read_headers(optind+1 == argc)==0)
  1585. X          if (optind+1 == argc)
  1586. X            printf("No mail\n");
  1587. X          else
  1588. X            printf("No messages in that folder!\n");
  1589. X        fclose(mailfile);
  1590. X      }
  1591. X
  1592. X      optind++;
  1593. X    }
  1594. X    exit(0);
  1595. X}
  1596. X
  1597. Xint
  1598. Xread_headers(user_mailbox)
  1599. Xint user_mailbox;
  1600. X{
  1601. X    /** Read the headers, output as found.  User-Mailbox is to guarantee
  1602. X        that we get a reasonably sensible message from the '-v' option
  1603. X     **/
  1604. X
  1605. X    char buffer[SLEN], from_whom[SLEN], subject[SLEN];
  1606. X    register int in_header = 0, count = 0;
  1607. X#ifdef MMDF
  1608. X    int newheader = 0;
  1609. X#endif /* MMDF */
  1610. X
  1611. X    while (fgets(buffer, SLEN, mailfile) != NULL) {
  1612. X      if (index(buffer, '\n') == NULL && !feof(mailfile)) {
  1613. X        int c;
  1614. X        while ((c = getc(mailfile)) != EOF && c != '\n')
  1615. X          ; /* keep reading */
  1616. X      }
  1617. X
  1618. X#ifdef MMDF
  1619. X          if (strcmp(buffer, MSG_SEPERATOR) == 0) {
  1620. X        newheader = !newheader;
  1621. X        if (newheader) {
  1622. X          subject[0] = '\0';
  1623. X          in_header = 1;
  1624. X        }
  1625. X      }
  1626. X#else
  1627. X      if (first_word(buffer,"From ")
  1628. X       && real_from(buffer, from_whom)) {
  1629. X        subject[0] = '\0';
  1630. X        in_header = 1;
  1631. X      }
  1632. X#endif /* MMDF */
  1633. X      else if (in_header) {
  1634. X#ifdef MMDF
  1635. X        if (first_word(buffer,"From "))
  1636. X          real_from(buffer, from_whom);
  1637. X#endif /* MMDF */
  1638. X        if (first_word(buffer,">From ")) 
  1639. X          forwarded(buffer, from_whom); /* return address */
  1640. X        else if (first_word(buffer,"Subject:") ||
  1641. X             first_word(buffer,"Re:")) {
  1642. X          if (subject[0] == '\0') {
  1643. X            remove_first_word(buffer);
  1644. X        strcpy(subject, buffer);
  1645. X          }
  1646. X        }
  1647. X        else if (first_word(buffer,"From:") ||
  1648. X            first_word(buffer, ">From:"))
  1649. X          parse_arpa_from(buffer, from_whom);
  1650. X        else if (buffer[0] == LINEFEED) {
  1651. X          if (verbose && count == 0)
  1652. X            printf("%s contains the following messages:\n\n",
  1653. X            user_mailbox?"Your mailbox" : "Folder");
  1654. X#ifdef MMDF
  1655. X          if (*from_whom == '\0')
  1656. X                strcpy(from_whom,username);
  1657. X#endif /* MMDF */
  1658. X          ++count;
  1659. X          show_header(count, from_whom, subject);
  1660. X          in_header = 0;
  1661. X        }
  1662. X      }
  1663. X    }
  1664. X    return(count);
  1665. X}
  1666. X
  1667. Xint
  1668. Xreal_from(buffer, who)
  1669. Xchar *buffer, *who;
  1670. X{
  1671. X    /***** returns true iff 's' has the seven 'from' fields,
  1672. X           initializing the who to the sender *****/
  1673. X
  1674. X    char junk[SLEN];
  1675. X
  1676. X    junk[0] = '\0';
  1677. X    sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
  1678. X                who, junk);
  1679. X    return(junk[0] != '\0');
  1680. X}
  1681. X
  1682. Xforwarded(buffer, who)
  1683. Xchar *buffer, *who;
  1684. X{
  1685. X    /** change 'from' and date fields to reflect the ORIGINATOR of 
  1686. X        the message by iteratively parsing the >From fields... **/
  1687. X
  1688. X    char machine[SLEN], buff[SLEN], holding_from[SLEN];
  1689. X
  1690. X    machine[0] = '\0';
  1691. X    holding_from[0] = '\0';
  1692. X    sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %s",
  1693. X                holding_from, machine);
  1694. X
  1695. X    if(machine[0] == '\0')    /* try for address with timezone in date */
  1696. X    sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
  1697. X                holding_from, machine);
  1698. X
  1699. X    if (machine[0] == '\0') /* try for srm address */
  1700. X      sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
  1701. X                holding_from, machine);
  1702. X
  1703. X    if (machine[0] == '\0')
  1704. X      sprintf(buff, holding_from[0] ? holding_from : "anonymous");
  1705. X    else
  1706. X      sprintf(buff,"%s!%s", machine, holding_from);
  1707. X
  1708. X    strncpy(who, buff, SLEN);
  1709. X}
  1710. X
  1711. Xremove_first_word(string)
  1712. Xchar *string;
  1713. X{    /** removes first word of string, ie up to first non-white space
  1714. X        following a white space! **/
  1715. X
  1716. X    register int loc;
  1717. X
  1718. X    for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) 
  1719. X        ;
  1720. X
  1721. X    while (string[loc] == ' ' || string[loc] == '\t')
  1722. X      loc++;
  1723. X    
  1724. X    move_left(string, loc);
  1725. X}
  1726. X
  1727. Xmove_left(string, chars)
  1728. Xchar string[];
  1729. Xint  chars;
  1730. X{
  1731. X    /** moves string chars characters to the left DESTRUCTIVELY **/
  1732. X
  1733. X    register int i;
  1734. X
  1735. X    chars--; /* index starting at zero! */
  1736. X
  1737. X    for (i=chars; string[i] != '\0' && string[i] != '\n'; i++)
  1738. X      string[i-chars] = string[i];
  1739. X
  1740. X    string[i-chars] = '\0';
  1741. X}
  1742. X
  1743. Xshow_header(count, from, subject)
  1744. Xint  count;
  1745. Xchar *from, *subject;
  1746. X{
  1747. X    /** output header in clean format, including abbreviation
  1748. X        of return address if more than one machine name is
  1749. X        contained within it! **/
  1750. X
  1751. X    char buffer[SLEN];
  1752. X    int  loc, i=0, exc=0, len;
  1753. X
  1754. X#ifndef INTERNET
  1755. X    char *p;
  1756. X    
  1757. X    if (chloc(from,'!') != -1 && chloc(from,'@') > 0) {
  1758. X      for (p=from;*p != '@'; p++) ;
  1759. X      *p = '\0';
  1760. X    }
  1761. X#endif
  1762. X
  1763. X    loc = strlen(from);
  1764. X
  1765. X    while (exc < 2 && loc > 0)
  1766. X      if (from[--loc] == '!')
  1767. X        exc++;
  1768. X
  1769. X    if (exc == 2) { /* lots of machine names!  Get last one */
  1770. X      loc++;
  1771. X      len = strlen(from);
  1772. X      while (loc < len && loc < SLEN)
  1773. X        buffer[i++] = from[loc++];
  1774. X      buffer[i] = '\0';
  1775. X      if (number)
  1776. X        printf("%3d: %-20s  %s\n", count, buffer, subject);
  1777. X      else
  1778. X        printf("%-20s  %s\n", buffer, subject);
  1779. X    }
  1780. X    else
  1781. X      if (number)
  1782. X        printf("%3d: %-20s  %s\n", count, from, subject);
  1783. X      else
  1784. X        printf("%-20s  %s\n", from, subject);
  1785. X}    
  1786. X
  1787. Xparse_arpa_from(buffer, newfrom)
  1788. Xchar *buffer, *newfrom;
  1789. X{
  1790. X    /** try to parse the 'From:' line given... It can be in one of
  1791. X        two formats:
  1792. X        From: Dave Taylor <hpcnou!dat>
  1793. X        or  From: hpcnou!dat (Dave Taylor)
  1794. X        Change 'newfrom' ONLY if sucessfully parsed this entry and
  1795. X        the resulting name is non-null! 
  1796. X    **/
  1797. X
  1798. X    char temp_buffer[SLEN], *temp;
  1799. X    register int i, j = 0, in_parens;
  1800. X
  1801. X    temp = (char *) temp_buffer;
  1802. X    temp[0] = '\0';
  1803. X
  1804. X    no_ret(buffer);        /* blow away '\n' char! */
  1805. X
  1806. X    if (lastch(buffer) == '>') {
  1807. X      for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' &&
  1808. X           buffer[i] != '('; i++)
  1809. X        temp[j++] = buffer[i];
  1810. X      temp[j] = '\0';
  1811. X    }
  1812. X    else if (lastch(buffer) == ')') {
  1813. X      in_parens = 1;
  1814. X      for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '<'; i--) {
  1815. X        switch(buffer[i]) {
  1816. X        case ')':    in_parens++;
  1817. X            break;
  1818. X        case '(':    in_parens--;
  1819. X            break;
  1820. X        }
  1821. X        if(!in_parens) break;
  1822. X        temp[j++] = buffer[i];
  1823. X      }
  1824. X      temp[j] = '\0';
  1825. X      reverse(temp);
  1826. X    }
  1827. X
  1828. X/* this stuff copied from src/addr_util.c */
  1829. X#ifdef USE_EMBEDDED_ADDRESSES
  1830. X
  1831. X    /** if we have a null string at this point, we must just have a 
  1832. X        From: line that contains an address only.  At this point we
  1833. X        can have one of a few possibilities...
  1834. X
  1835. X        From: address
  1836. X        From: <address>
  1837. X        From: address ()
  1838. X    **/
  1839. X      
  1840. X    if (strlen(temp) == 0) {
  1841. X      if (lastch(buffer) != '>') {       
  1842. X        for (i=strlen("From:");buffer[i] != '\0' && buffer[i] != '('; i++)
  1843. X          temp[j++] = buffer[i];
  1844. X        temp[j] = '\0';
  1845. X      }
  1846. X      else {    /* get outta '<>' pair, please! */
  1847. X        for (i=strlen(buffer)-2;buffer[i] != '<' && buffer[i] != ':';i--)
  1848. X          temp[j++] = buffer[i];
  1849. X        temp[j] = '\0';
  1850. X        reverse(temp);
  1851. X      }
  1852. X    }
  1853. X#endif
  1854. X
  1855. X    if (strlen(temp) > 0) {        /* mess with buffer... */
  1856. X
  1857. X      /* remove leading spaces... */
  1858. X
  1859. X      while (whitespace(temp[0]))
  1860. X        temp = (char *) (temp + 1);        /* increment address! */
  1861. X
  1862. X      /* remove trailing spaces... */
  1863. X
  1864. X      i = strlen(temp) - 1;
  1865. X
  1866. X      while (whitespace(temp[i]))
  1867. X       temp[i--] = '\0';
  1868. X
  1869. X      /* remove surrounding paired quotation marks */
  1870. X      if((temp[i] == '"') & (*temp == '"')) {
  1871. SHAR_EOF
  1872. echo "End of part 24"
  1873. echo "File utils/from.c is continued in part 25"
  1874. echo "25" > s2_seq_.tmp
  1875. exit 0
  1876.  
  1877. "File utils/answer.c is continued in part 24"
  1878. echo "24" > s2_seq_.tmp
  1879. exit 0
  1880.  
  1881. exit 0 # Just in case...
  1882.