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

  1. Subject:  v22i074:  ELM mail syste, release 2.3, Part15/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 118986f3 ccb18622 cf2fa780 2f06860a
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 74
  8. Archive-name: elm2.3/part15
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 15 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file src/expires.c continued
  15. #
  16. CurArch=15
  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/expires.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> src/expires.c
  28. X        if we consider a message to be expired on Jan 4, 88:
  29. X            01/04/88    in the United States
  30. X            04/01/88    in Europe
  31. X        so is the first field the month or the day?  Standard prob.
  32. X    **/
  33. X
  34. X    sscanf(date, "%s %s %s %s %s",
  35. X        word1, word2, word3, word4, word5);
  36. X
  37. X    if (strlen(word5) != 0) {    /* we have form #7 */
  38. X      day   = atoi(word1);
  39. X      month = month_number(word2);
  40. X      year  = atoi(word3);
  41. X      sscanf(word4, "%02d%*c%02d",
  42. X           &hour, &minute);
  43. X    }
  44. X    else if (strlen(word2) == 0) {    /* we have form #6 or form #5 */
  45. X      if (isdigit(word1[1]) && isdigit(word1[2]))      /* form #6 */
  46. X        sscanf(word1, "%02d%02d%02d%02d%02d%*c",
  47. X         &year, &month, &day, &hour, &minute);
  48. X    }
  49. X    else if (strlen(word4) != 0) {           /* form #1 or form #2 */
  50. X      if(isdigit(word2[0])) {           /* form #2 */
  51. X          month = month_number(word3);
  52. X          day   = atoi(word2);
  53. X          year  = atoi(word4);
  54. X      } else {                   /* form #1 */
  55. X          month = month_number(word2);
  56. X          day   = atoi(word3);
  57. X          year  = atoi(word4);
  58. X      }
  59. X    }
  60. X    else if (! isdigit(word1[0])) {           /* form #3 */
  61. X      month = month_number(word1);
  62. X      day   = atoi(word2);
  63. X      year  = atoi(word3);
  64. X    }
  65. X    else {                       /* form #4 */
  66. X      day   = atoi(word1);
  67. X      month = month_number(word2);
  68. X      year  = atoi(word3);
  69. X    }
  70. X
  71. X    if (day == 0 || year == 0)
  72. X      return;            /* we didn't get a valid date */
  73. X
  74. X    /** next let's get the current time and date, please **/
  75. X
  76. X    thetime = time((long *) 0);
  77. X
  78. X    timestruct = localtime(&thetime);
  79. X
  80. X    /** and compare 'em **/
  81. X
  82. X    if (year > timestruct->tm_year)
  83. X      return;
  84. X    else if (year < timestruct->tm_year)
  85. X      goto expire_message;
  86. X
  87. X    if (month > timestruct->tm_mon)
  88. X      return;
  89. X    else if (month < timestruct->tm_mon)
  90. X      goto expire_message;
  91. X
  92. X    if (day > timestruct->tm_mday)
  93. X      return;
  94. X    else if (day < timestruct->tm_mday)
  95. X      goto expire_message;
  96. X
  97. X    if (hour > timestruct->tm_hour)
  98. X      return;
  99. X    else if (hour < timestruct->tm_hour)
  100. X      goto expire_message;
  101. X
  102. X    if (minute > timestruct->tm_min)
  103. X      return;
  104. X
  105. Xexpire_message:
  106. X
  107. X    /** it's EXPIRED!  Yow!! **/
  108. X
  109. X    (*message_status) |= EXPIRED;
  110. X}
  111. SHAR_EOF
  112. echo "File src/expires.c is complete"
  113. chmod 0444 src/expires.c || echo "restore of src/expires.c fails"
  114. echo "x - extracting src/file.c (Text)"
  115. sed 's/^X//' << 'SHAR_EOF' > src/file.c &&
  116. X
  117. Xstatic char rcsid[] = "@(#)$Id: file.c,v 4.1 90/04/28 22:43:02 syd Exp $";
  118. X
  119. X/*******************************************************************************
  120. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  121. X *
  122. X *             Copyright (c) 1986, 1987 Dave Taylor
  123. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  124. X *******************************************************************************
  125. X * Bug reports, patches, comments, suggestions should be sent to:
  126. X *
  127. X *    Syd Weinstein, Elm Coordinator
  128. X *    elm@DSI.COM            dsinc!elm
  129. X *
  130. X *******************************************************************************
  131. X * $Log:    file.c,v $
  132. X * Revision 4.1  90/04/28  22:43:02  syd
  133. X * checkin of Elm 2.3 as of Release PL0
  134. X * 
  135. X *
  136. X ******************************************************************************/
  137. X
  138. X/** File I/O routines, mostly the save to file command...
  139. X
  140. X**/
  141. X
  142. X#ifdef PWDINSYS
  143. X#  include <sys/pwd.h>
  144. X#else
  145. X#  include <pwd.h>
  146. X#endif
  147. X
  148. X#include "headers.h"
  149. X#include <ctype.h>
  150. X#include <errno.h>
  151. X
  152. X#ifdef BSD
  153. X#undef tolower
  154. X#endif
  155. X
  156. Xextern int errno;
  157. X
  158. Xchar *error_name(), *error_description(), *strcpy(), *getenv(), *nameof();
  159. Xunsigned long sleep();
  160. X
  161. Xint
  162. Xsave(redraw, silently, delete)
  163. Xint *redraw, silently, delete;
  164. X{
  165. X    /** Save all tagged messages + current in a folder.  If no messages
  166. X        are tagged, save the current message instead!  This routine
  167. X        will return ZERO if the operation failed.
  168. X        'redraw' is set to TRUE iff we use the '?' and mess up
  169. X        the screen.  Pretty reasonable, eh?  If "silently" is set,
  170. X        then don't output the "D" character upon marking for
  171. X        deletion...
  172. X        If delete is set, then delete the saved messages, else
  173. X        we are just copying the messages without deletion.
  174. X    **/
  175. X
  176. X    register int tagged = 0, i, oldstat, appending = 0;
  177. X    int mesgnum;    /* message whose address is used for save-by-name fn */
  178. X    char filename[SLEN], address[LONG_STRING], buffer[LONG_STRING];
  179. X    static char helpmsg[LONG_STRING];
  180. X    FILE *save_file;
  181. X
  182. X    oldstat = headers[current-1]->status;    /* remember */
  183. X    *redraw = FALSE;
  184. X
  185. X    for (i=0; i < message_count; i++) {
  186. X      if (ison(headers[i]->status, TAGGED)) {
  187. X        if(!tagged)
  188. X          mesgnum = i;    /* first tagged msg -  use this one for
  189. X                 * save-by-name folder name */
  190. X        tagged++;
  191. X      }
  192. X    }
  193. X
  194. X    if (tagged == 0) {
  195. X      mesgnum = current-1;    /* use this one for save-by-name folder name */
  196. X      tagged = 1;
  197. X      setit(headers[current-1]->status, TAGGED);
  198. X    }
  199. X
  200. X    dprint(4, (debugfile, "%d message%s tagged for saving (save)\n", tagged,
  201. X        plural(tagged)));
  202. X
  203. X    while (1) {
  204. X
  205. X      PutLine2(LINES-2, 0, "%s message%s to: ",
  206. X          (delete ? "Save" : "Copy"), plural(tagged));
  207. X
  208. X      if (save_by_name) {
  209. X        /** build default filename to save to **/
  210. X        get_return(address, mesgnum);
  211. X        get_return_name(address, buffer, TRUE);
  212. X        sprintf(filename, "=%s", buffer);
  213. X      }
  214. X      else
  215. X        filename[0] = '\0';
  216. X
  217. X      if (tagged > 1)
  218. X        optionally_enter(filename, LINES-2, 19, FALSE, FALSE);
  219. X      else    
  220. X        optionally_enter(filename, LINES-2, 18, FALSE, FALSE);
  221. X  
  222. X
  223. X      if (strlen(filename) == 0) {  /** <return> means 'cancel', right? **/
  224. X        headers[current-1]->status = oldstat;    /* BACK! */
  225. X        return(0);
  226. X      }
  227. X     
  228. X      if (strcmp(filename,"?") == 0) {    /* user asked for listing */
  229. X        *redraw = TRUE;    /* set the flag so we know what to do later */
  230. X        if(!*helpmsg) {    /* format helpmsg if not yet done */
  231. X
  232. X          strcpy(helpmsg, "\n\r\n\rEnter: <nothing> to not ");
  233. X          strcat(helpmsg, (delete ? "save" : "copy"));
  234. X          strcat(helpmsg, " your message");
  235. X          strcat(helpmsg, (plural(tagged) ? "s" : ""));
  236. X          strcat(helpmsg, "\n\r       '>' to ");
  237. X          strcat(helpmsg, (delete ? "save" : "copy"));
  238. X          strcat(helpmsg, " your message");
  239. X          strcat(helpmsg, (plural(tagged) ? "s" : ""));
  240. X          strcat(helpmsg, " to your \"received\" folder (");
  241. X          strcat(helpmsg, nameof(recvd_mail));
  242. X          strcat(helpmsg, ")\n\r       '<' to ");
  243. X          strcat(helpmsg, (delete ? "save" : "copy"));
  244. X          strcat(helpmsg, " your message");
  245. X          strcat(helpmsg, (plural(tagged) ? "s" : ""));
  246. X          strcat(helpmsg, " to your \"sent\" folder (");
  247. X          strcat(helpmsg, nameof(sent_mail));
  248. X          strcat(helpmsg, ") \n\r       a filename");
  249. X          strcat(helpmsg, " (leading '=' denotes your folder directory ");
  250. X          strcat(helpmsg, folders);
  251. X          strcat(helpmsg, ").\n\r");
  252. X        }
  253. X
  254. X        list_folders(4, helpmsg);
  255. X        continue;
  256. X      }
  257. X
  258. X      /* else - got a folder name - check it out */
  259. X      if (! expand_filename(filename, TRUE)) {
  260. X        dprint(2, (debugfile,
  261. X          "Error: Failed on expansion of filename %s (save)\n", 
  262. X          filename));
  263. X        continue;
  264. X      }
  265. X      if ((errno = can_open(filename, "a"))) {
  266. X        error2("Cannot %s message to folder %s!",
  267. X          delete ? "save":"copy", filename);
  268. X        continue;
  269. X      }
  270. X      break;    /* got a valid filename */
  271. X    }
  272. X
  273. X    save_file_stats(filename);
  274. X
  275. X    if (access(filename,ACCESS_EXISTS)== 0)     /* already there!! */
  276. X      appending = 1;
  277. X      
  278. X    dprint(4,(debugfile, "Saving mail to folder '%s'...\n", filename));
  279. X
  280. X    if ((save_file = fopen(filename,"a")) == NULL) {
  281. X      dprint(2, (debugfile,
  282. X        "Error: couldn't append to specified folder %s (save)\n", 
  283. X        filename));
  284. X      error1("Couldn't append to folder %s!", filename);
  285. X      headers[current-1]->status = oldstat;    /* BACK! */
  286. X      return(0); 
  287. X    }
  288. X
  289. X    /* if we need a redraw that means index screen no longer present
  290. X     * so whatever silently was, now it's true - we can't show those
  291. X     * delete markings.
  292. X     */
  293. X    if(*redraw) silently = TRUE;
  294. X
  295. X    for (i=0; i < message_count; i++)     /* save each tagged msg */
  296. X      if (headers[i]->status & TAGGED)
  297. X        save_message(i, filename, save_file, (tagged > 1), appending++, 
  298. X             silently, delete);
  299. X
  300. X    fclose(save_file);
  301. X
  302. X    restore_file_stats(filename);
  303. X
  304. X    if (tagged > 1)
  305. X      error2("Message%s %s.", plural(tagged), delete ? "saved": "copied");
  306. X    return(1);
  307. X}
  308. X
  309. Xint
  310. Xsave_message(number, filename, fd, pause, appending, silently, delete)
  311. Xint number, pause, appending, silently, delete;
  312. Xchar *filename;
  313. XFILE *fd;
  314. X{
  315. X    /** Save an actual message to a folder.  This is called by 
  316. X        "save()" only!  The parameters are the message number,
  317. X        and the name and file descriptor of the folder to save to.
  318. X        If 'pause' is true, a sleep(2) will be done after the
  319. X        saved message appears on the screen...
  320. X        'appending' is only true if the folder already exists 
  321. X        If 'delete' is true, mark the message for deletion.
  322. X    **/
  323. X
  324. X    register int save_current, is_new;
  325. X    
  326. X    dprint(4, (debugfile, "\tSaving message %d to folder...\n", number));
  327. X
  328. X    save_current = current;
  329. X    current = number+1;
  330. X
  331. X    /* change status from NEW before copy and reset to what it was
  332. X     * so that copy doesn't look new, but we can preserve new status
  333. X     * of message in this mailfile. This is important because if
  334. X     * user does a resync, we don't want NEW status to be lost.
  335. X     * I.e. NEW becomes UNREAD when we "really" leave a mailfile.
  336. X     */
  337. X    if(is_new = ison(headers[number]->status, NEW))
  338. X      clearit(headers[number]->status, NEW);
  339. X    copy_message("", fd, FALSE, FALSE, TRUE, FALSE);
  340. X    if(is_new)
  341. X      setit(headers[number]->status, NEW);
  342. X    current = save_current;
  343. X
  344. X    if (delete)
  345. X      setit(headers[number]->status, DELETED); /* deleted, but ...   */
  346. X    clearit(headers[number]->status, TAGGED);  /* not tagged anymore */
  347. X
  348. X    if (appending)
  349. X      error2("Message %d appended to folder %s.", number+1, filename);
  350. X    else
  351. X      error3("Message %d %s to folder %s.", number+1,
  352. X         delete ? "saved" : "copied", filename);
  353. X
  354. X    if (! silently)
  355. X      show_new_status(number);    /* update screen, if needed */
  356. X
  357. X    if (pause && (!silently) && (!appending))
  358. X      sleep(2);
  359. X}
  360. X
  361. Xint
  362. Xexpand_filename(filename, use_cursor_control)
  363. Xchar *filename;
  364. Xint use_cursor_control;
  365. X{
  366. X    /** Expands    ~/    to the current user's home directory
  367. X            ~user/    to the home directory of "user"
  368. X            =,+,%    to the user's folder's directory
  369. X            !    to the user's incoming mailbox
  370. X            >    to the user's received folder
  371. X            <    to the user's sent folder
  372. X            shell variables (begun with $)
  373. X
  374. X        Returns     1    upon proper expansions
  375. X            0    upon failed expansions
  376. X     **/
  377. X
  378. X    char temp_filename[SLEN], varname[SLEN],
  379. X        env_value[SLEN], logname[SLEN], *ptr;
  380. X    register int iindex;
  381. X    struct passwd *pass, *getpwnam();
  382. X    char *getenv();
  383. X
  384. X    ptr = filename;
  385. X    while (*ptr == ' ') ptr++;    /* leading spaces GONE! */
  386. X    strcpy(temp_filename, ptr);
  387. X
  388. X    /** New stuff - make sure no illegal char as last **/
  389. X    if (lastch(temp_filename) == '\n' || lastch(temp_filename) == '\r')
  390. X      lastch(temp_filename) = '\0';
  391. X      
  392. X    /** Strip off any trailing backslashes **/
  393. X    while (lastch(temp_filename) == '\\')
  394. X        lastch(temp_filename) = '\0';
  395. X
  396. X    if (temp_filename[0] == '~') {
  397. X      if(temp_filename[1] == '/')
  398. X        sprintf(filename, "%s%s%s",
  399. X          home, (lastch(home) != '/' ? "/" : ""), &temp_filename[2]);
  400. X      else {
  401. X        for(ptr = &temp_filename[1], iindex = 0; *ptr && *ptr != '/'; ptr++, iindex++)
  402. X          logname[iindex] = *ptr;
  403. X        logname[iindex] = '\0';
  404. X        if((pass = getpwnam(logname)) == NULL) {
  405. X          dprint(3,(debugfile, 
  406. X              "Error: Can't get home directory for %s (%s)\n",
  407. X              logname, "expand_filename"));
  408. X          if(use_cursor_control)
  409. X        error1("Don't know what the home directory of \"%s\" is!",
  410. X            logname);
  411. X          else
  412. X        printf(
  413. X            "\n\rDon't know what the home directory of \"%s\" is!\n\r",
  414. X            logname);
  415. X          return(0);
  416. X        }
  417. X        sprintf(filename, "%s%s", pass->pw_dir, ptr);
  418. X      }
  419. X
  420. X    }
  421. X    else if (temp_filename[0] == '=' || temp_filename[0] == '+' || 
  422. X          temp_filename[0] == '%') {
  423. X      sprintf(filename, "%s%s%s", folders, 
  424. X        (temp_filename[1] != '/' && lastch(folders) != '/')? "/" : "",
  425. X          &temp_filename[1]);
  426. X    }
  427. X    else if (temp_filename[0] == '$') {    /* env variable! */
  428. X      for(ptr = &temp_filename[1], iindex = 0; isalnum(*ptr); ptr++, iindex++)
  429. X        varname[iindex] = *ptr;
  430. X      varname[iindex] = '\0';
  431. X
  432. X      env_value[0] = '\0';            /* null string for strlen! */
  433. X      if (getenv(varname) != NULL)
  434. X        strcpy(env_value, getenv(varname));
  435. X
  436. X      if (strlen(env_value) == 0) {
  437. X        dprint(3,(debugfile, 
  438. X            "Error: Can't expand environment variable $%s (%s)\n",
  439. X            varname, "expand_filename"));
  440. X        if(use_cursor_control)
  441. X          error1("Don't know what the value of $%s is!", varname);
  442. X        else
  443. X          printf("\n\rDon't know what the value of $%s is!\n\r", varname);
  444. X        return(0);
  445. X      }
  446. X
  447. X      sprintf(filename, "%s%s%s", env_value, 
  448. X        (*ptr != '/' && lastch(env_value) != '/')? "/" : "", ptr);
  449. X
  450. X    } else if (strcmp(temp_filename, "!") == 0) {
  451. X      strcpy(filename, defaultfile);
  452. X    } else if (strcmp(temp_filename, ">") == 0) {
  453. X      strcpy(filename, recvd_mail);
  454. X    } else if (strcmp(temp_filename, "<") == 0) {
  455. X      strcpy(filename, sent_mail);
  456. X    } else
  457. X      strcpy(filename, temp_filename);
  458. X      
  459. X    return(1);
  460. X}
  461. SHAR_EOF
  462. chmod 0444 src/file.c || echo "restore of src/file.c fails"
  463. echo "x - extracting src/file_util.c (Text)"
  464. sed 's/^X//' << 'SHAR_EOF' > src/file_util.c &&
  465. X
  466. Xstatic char rcsid[] = "@(#)$Id: file_util.c,v 4.1 90/04/28 22:43:04 syd Exp $";
  467. X
  468. X/*******************************************************************************
  469. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  470. X *
  471. X *             Copyright (c) 1986, 1987 Dave Taylor
  472. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  473. X *******************************************************************************
  474. X * Bug reports, patches, comments, suggestions should be sent to:
  475. X *
  476. X *    Syd Weinstein, Elm Coordinator
  477. X *    elm@DSI.COM            dsinc!elm
  478. X *
  479. X *******************************************************************************
  480. X * $Log:    file_util.c,v $
  481. X * Revision 4.1  90/04/28  22:43:04  syd
  482. X * checkin of Elm 2.3 as of Release PL0
  483. X * 
  484. X *
  485. X ******************************************************************************/
  486. X
  487. X/** File oriented utility routines for ELM 
  488. X
  489. X**/
  490. X
  491. X#include "headers.h"
  492. X#include <sys/types.h>
  493. X#include <sys/stat.h>
  494. X#include <ctype.h>
  495. X#include <errno.h>
  496. X
  497. X#ifdef BSD
  498. X# undef tolower
  499. X#endif
  500. X
  501. X#include <signal.h>
  502. X#include <errno.h>
  503. X
  504. X#ifdef BSD
  505. X# include <sys/wait.h>
  506. X#endif
  507. X
  508. Xextern int errno;        /* system error number */
  509. X
  510. Xchar *error_name(), *error_description(), *strcpy(), *getlogin();
  511. Xlong  fsize();
  512. X
  513. Xlong
  514. Xbytes(name)
  515. Xchar *name;
  516. X{
  517. X    /** return the number of bytes in the specified file.  This
  518. X        is to check to see if new mail has arrived....  (also
  519. X        see "fsize()" to see how we can get the same information
  520. X        on an opened file descriptor slightly more quickly)
  521. X    **/
  522. X
  523. X    int ok = 1;
  524. X    extern int errno;    /* system error number! */
  525. X    struct stat buffer;
  526. X
  527. X    if (stat(name, &buffer) != 0)
  528. X      if (errno != 2) {
  529. X        dprint(1,(debugfile,
  530. X             "Error: errno %s on fstat of file %s (bytes)\n", 
  531. X             error_name(errno), name));
  532. X        Write_to_screen("\n\rError attempting fstat on file %s!\n\r",
  533. X             1, name);
  534. X        Write_to_screen("** %s - %s. **\n\r", 2, error_name(errno),
  535. X          error_description(errno));
  536. X        emergency_exit();
  537. X      }
  538. X      else
  539. X        ok = 0;
  540. X    
  541. X    return(ok ? (long) buffer.st_size : 0L);
  542. X}
  543. X
  544. Xint
  545. Xcan_access(file, mode)
  546. Xchar *file; 
  547. Xint   mode;
  548. X{
  549. X    /** returns ZERO iff user can access file or "errno" otherwise **/
  550. X
  551. X    int the_stat = 0, pid, w; 
  552. X    struct stat stat_buf;
  553. X    void _exit(), exit();
  554. X#if defined(BSD) && !defined(WEXITSTATUS)
  555. X    union wait status;
  556. X#else
  557. X    int status;
  558. X#endif
  559. X#ifdef VOIDSIG
  560. X    register void (*istat)(), (*qstat)();
  561. X#else
  562. X    register int (*istat)(), (*qstat)();
  563. X#endif
  564. X    
  565. X#ifdef VFORK
  566. X    if ((pid = vfork()) == 0) {
  567. X#else
  568. X    if ((pid = fork()) == 0) {
  569. X#endif
  570. X      setgid(groupid);
  571. X      setuid(userid);        /** back to normal userid **/
  572. X
  573. X      errno = 0;
  574. X
  575. X      if (access(file, mode) == 0) 
  576. X        _exit(0);
  577. X      else 
  578. X        _exit(errno != 0? errno : 1);    /* never return zero! */
  579. X      _exit(127);
  580. X    }
  581. X
  582. X    istat = signal(SIGINT, SIG_IGN);
  583. X    qstat = signal(SIGQUIT, SIG_IGN);
  584. X
  585. X    while ((w = wait(&status)) != pid && w != -1)
  586. X        ;
  587. X
  588. X#if    defined(WEXITSTATUS)
  589. X    /* Use POSIX macro if defined */
  590. X    the_stat = WEXITSTATUS(status);
  591. X#else
  592. X#ifdef BSD
  593. X    the_stat = status.w_retcode;
  594. X#else
  595. X    the_stat = status >> 8;
  596. X#endif
  597. X#endif    /*WEXITSTATUS*/
  598. X
  599. X    signal(SIGINT, istat);
  600. X    signal(SIGQUIT, qstat);
  601. X    if (the_stat == 0) {
  602. X      if (stat(file, &stat_buf) == 0) {
  603. X        w = stat_buf.st_mode & S_IFMT;
  604. X#ifdef S_IFLNK
  605. X        if (w != S_IFREG && w != S_IFLNK)
  606. X#else
  607. X        if (w != S_IFREG)
  608. X#endif
  609. X          the_stat = 1;
  610. X      }
  611. X    }
  612. X
  613. X    return(the_stat);
  614. X}
  615. X
  616. Xint
  617. Xcan_open(file, mode)
  618. Xchar *file, *mode;
  619. X{
  620. X    /** Returns 0 iff user can open the file.  This is not
  621. X        the same as can_access - it's used for when the file might
  622. X        not exist... **/
  623. X
  624. X    FILE *fd;
  625. X    int the_stat = 0, pid, w, preexisted = 0; 
  626. X    void _exit(), exit();
  627. X#if defined(BSD) && !defined(WEXITSTATUS)
  628. X    union wait status;
  629. X#else
  630. X    int status;
  631. X#endif
  632. X#ifdef VOIDSIG
  633. X    register void (*istat)(), (*qstat)();
  634. X#else
  635. X    register int (*istat)(), (*qstat)();
  636. X#endif
  637. X    
  638. X#ifdef VFORK
  639. X    if ((pid = vfork()) == 0) {
  640. X#else
  641. X    if ((pid = fork()) == 0) {
  642. X#endif
  643. X      setgid(groupid);
  644. X      setuid(userid);        /** back to normal userid **/
  645. X      errno = 0;
  646. X      if (access(file, ACCESS_EXISTS) == 0)
  647. X        preexisted = 1;
  648. X      if ((fd = fopen(file, mode)) == NULL)
  649. X        _exit(errno);
  650. X      else {
  651. X        fclose(fd);        /* don't just leave it open! */
  652. X        if(!preexisted)    /* don't leave it if this test created it! */
  653. X          unlink(file);
  654. X        _exit(0);
  655. X      }
  656. X      _exit(127);
  657. X    }
  658. X
  659. X    istat = signal(SIGINT, SIG_IGN);
  660. X    qstat = signal(SIGQUIT, SIG_IGN);
  661. X
  662. X    while ((w = wait(&status)) != pid && w != -1)
  663. X        ;
  664. X
  665. X#ifdef WEXITSTATUS
  666. X    the_stat = WEXITSTATUS(status);
  667. X#else
  668. X#ifdef BSD
  669. X    the_stat = status.w_retcode;
  670. X#else
  671. X    the_stat = status >> 8;
  672. X#endif
  673. X#endif /*WEXITSTATUS*/
  674. X    
  675. X    signal(SIGINT, istat);
  676. X    signal(SIGQUIT, qstat);
  677. X
  678. X    return(the_stat);
  679. X}
  680. X
  681. Xint
  682. Xcopy(from, to)
  683. Xchar *from, *to;
  684. X{
  685. X    /** this routine copies a specified file to the destination
  686. X        specified.  Non-zero return code indicates that something
  687. X        dreadful happened! **/
  688. X
  689. X    FILE *from_file, *to_file;
  690. X    char buffer[VERY_LONG_STRING];
  691. X    
  692. X    if ((from_file = fopen(from, "r")) == NULL) {
  693. X      dprint(1, (debugfile, "Error: could not open %s for reading (copy)\n",
  694. X         from));
  695. X      error1("Could not open file %s.", from);
  696. X      return(1);
  697. X    }
  698. X
  699. X    if ((to_file = fopen(to, "w")) == NULL) {
  700. X      dprint(1, (debugfile, "Error: could not open %s for writing (copy)\n",
  701. X         to));
  702. X      error1("Could not open file %s.", to);
  703. X      return(1);
  704. X    }
  705. X
  706. X    while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
  707. X      if (fputs(buffer, to_file) == EOF) {
  708. X          Write_to_screen("\n\rWrite failed to tempfile in copy\n\r", 0);
  709. X          perror(to);
  710. X          fclose(to_file);
  711. X          fclose(from_file);
  712. X          return(1);
  713. X      }
  714. X    fclose(from_file);
  715. X        if (fclose(to_file) == EOF) {
  716. X      Write_to_screen("\n\rClose failed on tempfile in copy\n\r", 0);
  717. X      perror(to);
  718. X      return(1);
  719. X    }
  720. X    chown( to, userid, groupid);
  721. X
  722. X    return(0);
  723. X}
  724. X
  725. Xint
  726. Xappend(fd, filename)
  727. XFILE *fd;
  728. Xchar *filename;
  729. X{
  730. X    /** This routine appends the specified file to the already
  731. X        open file descriptor.. Returns non-zero if fails.  **/
  732. X
  733. X    FILE *my_fd;
  734. X    char buffer[VERY_LONG_STRING];
  735. X    
  736. X    if ((my_fd = fopen(filename, "r")) == NULL) {
  737. X      dprint(1, (debugfile,
  738. X        "Error: could not open %s for reading (append)\n", filename));
  739. X      return(1);
  740. X    }
  741. X
  742. X    while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL)
  743. X      if (fputs(buffer, fd) == EOF) {
  744. X          Write_to_screen("\n\rWrite failed to tempfile in append\n\r", 0);
  745. X          perror(filename);
  746. X          rm_temps_exit();
  747. X      }
  748. X
  749. X    if (fclose(my_fd) == EOF) {
  750. X      Write_to_screen("\n\rClose failed on tempfile in append\n\r", 0);
  751. X      perror(filename);
  752. X      rm_temps_exit();
  753. X    }
  754. X
  755. X    return(0);
  756. X}
  757. X
  758. X#define FORWARDSIGN    "Forward to "
  759. Xint
  760. Xcheck_mailfile_size(mfile)
  761. Xchar *mfile;
  762. X{
  763. X    /** Check to ensure we have mail.  Only used with the '-z'
  764. X        starting option. So we output a diagnostic if there is
  765. X        no mail to read (including  forwarding).
  766. X        Return 0 if there is mail,
  767. X           <0 if no permission to check,
  768. X           1 if no mail,
  769. X           2 if no mail because mail is being forwarded.
  770. X     **/
  771. X
  772. X    char firstline[SLEN];
  773. X    int retcode;
  774. X    struct stat statbuf;
  775. X    FILE *fp;
  776. X
  777. X    /* see if file exists first */
  778. X    if (access(mfile, ACCESS_EXISTS) != 0)
  779. X      retcode = 1;                    /* no file */
  780. X
  781. X    /* exists - now see if user has read access */
  782. X    else if (can_access(mfile, READ_ACCESS) != 0)
  783. X      retcode = -1;                    /* no perm */
  784. X
  785. X    /* read access - now see if file has a reasonable size */
  786. X    else if ((fp = fopen(mfile, "r")) == NULL)
  787. X      retcode = -1;        /* no perm? should have detected this above! */
  788. X    else if (fstat(fileno(fp), &statbuf) == -1) 
  789. X      retcode = -1;                    /* arg error! */
  790. X    else if (statbuf.st_size < 2)        
  791. X      retcode = 1;    /* empty or virtually empty, e.g. just a newline */
  792. X
  793. X    /* file has reasonable size - see if forwarding */
  794. X    else if (fgets (firstline, SLEN, fp) == NULL)
  795. X      retcode = 1;         /* empty? should have detected this above! */
  796. X    else if (first_word(firstline, FORWARDSIGN))
  797. X      retcode = 2;                    /* forwarding */
  798. X
  799. X    /* not forwarding - so file must have some mail in it */
  800. X    else
  801. X      retcode = 0;
  802. X
  803. X    /* now display the appropriate message if there isn't mail in it */
  804. X    switch(retcode) {
  805. X
  806. X    case -1:    printf("You have no permission to read %s!\n\r", mfile);
  807. X            break;
  808. X    case 1:        printf("You have no mail.\n\r");
  809. X            break;
  810. X    case 2:        no_ret(firstline) /* remove newline before using */
  811. X            printf("Your mail is being forwarded to %s.\n\r",
  812. X              firstline + strlen(FORWARDSIGN));
  813. X            break;
  814. X    }
  815. X    return(retcode);
  816. X}
  817. X
  818. Xcreate_readmsg_file()
  819. X{
  820. X    /** Creates the file ".current" in the users home directory
  821. X        for use with the "readmsg" program.
  822. X    **/
  823. X
  824. X    FILE *fd;
  825. X    char buffer[SLEN];
  826. X
  827. X    sprintf(buffer,"%s/%s", home, readmsg_file);
  828. X
  829. X    if ((fd = fopen (buffer, "w")) == NULL) {
  830. X      dprint(1, (debugfile, 
  831. X         "Error: couldn't create file %s - error %s (%s)\n",
  832. X         buffer, error_name(errno), "create_readmsg_file"));
  833. X      return;    /* no error to user */
  834. X    }
  835. X
  836. X    if (current)
  837. X      fprintf(fd, "%d\n", headers[current-1]->index_number);
  838. X    else
  839. X      fprintf(fd, "\n");
  840. X
  841. X    fclose(fd);
  842. X    chown( buffer, userid, groupid);
  843. X}
  844. X
  845. Xlong fsize(fd)
  846. XFILE *fd;
  847. X{
  848. X    /** return the size of the current file pointed to by the given
  849. X        file descriptor - see "bytes()" for the same function with
  850. X        filenames instead of open files...
  851. X    **/
  852. X
  853. X    struct stat buffer;
  854. X
  855. X    (void) fstat(fileno(fd), &buffer);
  856. X
  857. X    return( (long) buffer.st_size );
  858. X}
  859. SHAR_EOF
  860. chmod 0444 src/file_util.c || echo "restore of src/file_util.c fails"
  861. echo "x - extracting src/fileio.c (Text)"
  862. sed 's/^X//' << 'SHAR_EOF' > src/fileio.c &&
  863. X
  864. Xstatic char rcsid[] = "@(#)$Id: fileio.c,v 4.1 90/04/28 22:43:06 syd Exp $";
  865. X
  866. X/*******************************************************************************
  867. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  868. X *
  869. X *             Copyright (c) 1986, 1987 Dave Taylor
  870. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  871. X *******************************************************************************
  872. X * Bug reports, patches, comments, suggestions should be sent to:
  873. X *
  874. X *    Syd Weinstein, Elm Coordinator
  875. X *    elm@DSI.COM            dsinc!elm
  876. X *
  877. X *******************************************************************************
  878. X * $Log:    fileio.c,v $
  879. X * Revision 4.1  90/04/28  22:43:06  syd
  880. X * checkin of Elm 2.3 as of Release PL0
  881. X * 
  882. X *
  883. X ******************************************************************************/
  884. X
  885. X/** File I/O routines, including deletion from the folder! 
  886. X
  887. X**/
  888. X
  889. X#include "headers.h"
  890. X#include <sys/types.h>
  891. X#include <sys/stat.h>
  892. X#include <ctype.h>
  893. X#include <errno.h>
  894. X
  895. X#ifdef BSD
  896. X#undef tolower
  897. X#endif
  898. X
  899. Xextern int errno;
  900. X
  901. Xchar *error_name(), *index();
  902. X
  903. Xcopy_message(prefix, dest_file, remove_header, remote, update_status, mmdf_head)
  904. Xchar *prefix;
  905. XFILE *dest_file;
  906. Xint  remove_header, remote, update_status, mmdf_head;
  907. X{
  908. X    /** Copy current message to destination file, with optional 'prefix' 
  909. X        as the prefix for each line.  If remove_header is true, it will 
  910. X        skip lines in the message until it finds the end of header line...
  911. X        then it will start copying into the file... If remote is true
  912. X        then it will append "remote from <hostname>" at the end of the
  913. X        very first line of the file (for remailing) 
  914. X
  915. X        If "forwarding" is true then it'll do some nice things to
  916. X        ensure that the forwarded message looks pleasant; e.g. remove
  917. X        stuff like ">From " lines and "Received:" lines.
  918. X
  919. X        If "update_status" is true then it will write a new Status:
  920. X        line at the end of the headers.  It never copies an existing one.
  921. X    **/
  922. X
  923. X    char buffer[SLEN];
  924. X    register struct header_rec *current_header = headers[current-1];
  925. X    register int  lines, front_line, next_front,
  926. X          in_header = 1, first_line = TRUE, ignoring = FALSE;
  927. X    int    end_header = 0;
  928. X
  929. X      /** get to the first line of the message desired **/
  930. X
  931. X    if (fseek(mailfile, current_header->offset, 0) == -1) {
  932. X       dprint(1, (debugfile, 
  933. X        "ERROR: Attempt to seek %d bytes into file failed (%s)",
  934. X        current_header->offset, "copy_message"));
  935. X       error1("ELM [seek] failed trying to read %d bytes into file.",
  936. X         current_header->offset);
  937. X       return;
  938. X    }
  939. X
  940. X    /* how many lines in message? */
  941. X
  942. X    lines = current_header->lines;
  943. X
  944. X    /* set up for forwarding just in case... */
  945. X
  946. X    if (forwarding)
  947. X      remove_header = FALSE;
  948. X
  949. X    /* now while not EOF & still in message... copy it! */
  950. X
  951. X    next_front = TRUE;
  952. X
  953. X    while (lines) {
  954. X      if (fgets(buffer, SLEN, mailfile) == NULL)
  955. X        break;
  956. X
  957. X      front_line = next_front;
  958. X
  959. X      if(buffer[strlen(buffer)-1] == '\n') {
  960. X    lines--;    /* got a full line */
  961. X    next_front = TRUE;
  962. X      }
  963. X      else
  964. X    next_front = FALSE;
  965. X      
  966. X      if (front_line && ignoring)
  967. X    ignoring = whitespace(buffer[0]);
  968. X
  969. X      if (ignoring)
  970. X    continue;
  971. X
  972. X#ifdef MMDF
  973. X      if (mmdf_head && strcmp(buffer, MSG_SEPERATOR) == 0)
  974. X    continue;
  975. X#endif /* MMDF */
  976. X
  977. X      /* are we still in the header? */
  978. X
  979. X      if (in_header && front_line) {
  980. X    if (strlen(buffer) < 2) {
  981. X      in_header = 0;
  982. X      end_header = -1;
  983. X    }
  984. X    else if (!isspace(*buffer)
  985. X          && index(buffer, ':') == NULL
  986. X#ifdef MMDF
  987. X          && strcmp(buffer, MSG_SEPERATOR) != 0
  988. X#endif /* MMDF */
  989. X        ) {
  990. X      in_header = 0;
  991. X      end_header = 1;
  992. X    } else if (in_header && remote && first_word(buffer, "Sender:")) {
  993. X      continue;
  994. X    }
  995. X    if (end_header) {
  996. X      if (update_status) {
  997. X          if (isoff(current_header->status, NEW)) {
  998. X        if (ison(current_header->status, UNREAD)) {
  999. X          if (fprintf(dest_file, "%sStatus: O\n", prefix) == EOF) {
  1000. X            Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1001. X            dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1002. X            rm_temps_exit();
  1003. X          }
  1004. X        } else    /* read */
  1005. X#ifdef BSD
  1006. X          if (fprintf(dest_file, "%sStatus: OR\n", prefix) == EOF) {
  1007. X#else
  1008. X          if (fprintf(dest_file, "%sStatus: RO\n", prefix) == EOF) {
  1009. X#endif
  1010. X            Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1011. X            dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1012. X            rm_temps_exit();
  1013. X          }
  1014. X        update_status = FALSE; /* do it only once */
  1015. X          }    /* else if NEW - indicate NEW with no Status: line. This is
  1016. X         * important if we resync a mailfile - we don't want
  1017. X         * NEW status lost when we copy each message out.
  1018. X         * It is the responsibility of the function that calls
  1019. X         * this function to unset NEW as appropriate to its
  1020. X         * reason for using this function to copy a message
  1021. X         */
  1022. X
  1023. X        /*
  1024. X         * add the missing newline for RFC 822
  1025. X         */
  1026. X          if (end_header > 0) {
  1027. X        /* add the missing newline for RFC 822 */
  1028. X        if (fprintf(dest_file, "\n") == EOF) {
  1029. X          Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1030. X          dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1031. X          rm_temps_exit();
  1032. X        }
  1033. X          }
  1034. X      }
  1035. X    }
  1036. X      }
  1037. X
  1038. X      if (in_header) {
  1039. X    /* Process checks while in header area */
  1040. X
  1041. X    if (remove_header) {
  1042. X      ignoring = TRUE;
  1043. X      continue;
  1044. X    }
  1045. X
  1046. X    /* add remote on to front? */
  1047. X    if (first_line && remote) {
  1048. X      no_ret(buffer);
  1049. X#ifndef MMDF
  1050. X      if (fprintf(dest_file, "%s%s remote from %s\n",
  1051. X          prefix, buffer, hostname) == EOF) {
  1052. X        Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1053. X        dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1054. X        rm_temps_exit();
  1055. X      }
  1056. X#else
  1057. X      if (first_word(buffer, "From ")) {
  1058. X        if (fprintf(dest_file, "%s%s remote from %s\n",
  1059. X            prefix, buffer, hostname) == EOF) {
  1060. X        Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1061. X        dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1062. X        rm_temps_exit();
  1063. X        }
  1064. X      } else {
  1065. X        if (fprintf(dest_file, "%s%s\n", prefix, buffer) == EOF) {
  1066. X        Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1067. X        dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1068. X        rm_temps_exit();
  1069. X        }
  1070. X      }
  1071. X#endif /* MMDF */
  1072. X      first_line = FALSE;
  1073. X      continue;
  1074. X    }
  1075. X
  1076. X    if (!forwarding) {
  1077. X      if(! first_word(buffer, "Status:")) {
  1078. X        if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
  1079. X              dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1080. X          rm_temps_exit();
  1081. X          }
  1082. X        continue;
  1083. X      } else {
  1084. X        ignoring = TRUE;
  1085. X        continue;    /* we will output a new Status: line later, if desired. */
  1086. X      }
  1087. X    }
  1088. X    else { /* forwarding */
  1089. X
  1090. X      if (first_word(buffer, "Received:"   ) ||
  1091. X          first_word(buffer, ">From"       ) ||
  1092. X          first_word(buffer, "Status:"     ) ||
  1093. X          first_word(buffer, "Return-Path:"))
  1094. X          ignoring = TRUE;
  1095. X      else
  1096. X        if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
  1097. X              dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1098. X          rm_temps_exit();
  1099. X          }
  1100. X    }
  1101. X      }
  1102. X      else { /* not in header */
  1103. X        /* Process checks that occur after the header area */
  1104. X
  1105. X#ifndef MMDF
  1106. X    if(first_word(buffer, "From ") && (real_from(buffer, NULL))) {
  1107. X      dprint(1, (debugfile,
  1108. X         "\n*** Internal Problem...Tried to add the following;\n"));
  1109. X      dprint(1, (debugfile,
  1110. X         "  '%s'\nto output file (copy_message) ***\n", buffer));
  1111. X      break;    /* STOP NOW! */
  1112. X    }
  1113. X#endif /* MMDF */
  1114. X
  1115. X    if (fprintf(dest_file, "%s%s", prefix, buffer) == EOF) {
  1116. X      Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1117. X      dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1118. X      rm_temps_exit();
  1119. X    }
  1120. X      }
  1121. X    }
  1122. X#ifndef MMDF
  1123. X    if (strlen(buffer) + strlen(prefix) > 1)
  1124. X    if (fprintf(dest_file, "\n") == EOF) {    /* blank line to keep mailx happy *sigh* */
  1125. X      Write_to_screen("\n\rWrite in copy_message failed\n\r", 0);
  1126. X      dprint(1, (debugfile,"\n*** Fprint failed on copy_message;\n"));
  1127. X      rm_temps_exit();
  1128. X    }
  1129. X#endif /* MMDF */
  1130. X}
  1131. X
  1132. Xstatic struct stat saved_buf;
  1133. Xstatic char saved_fname[SLEN];
  1134. X
  1135. Xint
  1136. Xsave_file_stats(fname)
  1137. Xchar *fname;
  1138. X{
  1139. X    /* if fname exists, save the owner, group, mode and filename.
  1140. X     * otherwise flag nothing saved. Return 0 if saved, else -1.
  1141. X     */
  1142. X
  1143. X    if(stat(fname, &saved_buf) != -1) {
  1144. X      (void)strcpy(saved_fname, fname);
  1145. X      dprint(2, (debugfile,
  1146. X        "** saved stats for file owner = %d group = %d mode = %o %s **\n",
  1147. X        saved_buf.st_uid, saved_buf.st_gid, saved_buf.st_mode, fname));
  1148. X      return(0);
  1149. X    }
  1150. X    dprint(2, (debugfile,
  1151. X      "** couldn't save stats for file %s [errno=%d] **\n",
  1152. X      fname, errno));
  1153. X    return(-1);
  1154. X
  1155. X}
  1156. X
  1157. Xrestore_file_stats(fname)
  1158. Xchar *fname;
  1159. X{
  1160. X    /* if fname matches the saved file name, set the owner and group
  1161. X     * of fname to the saved owner, group and mode,
  1162. X     * else to the userid and groupid of the user and to 700.
  1163. X     * Return    -1 if the  either mode or owner/group not set
  1164. X     *        0 if the default values were used
  1165. X     *        1 if the saved values were used
  1166. X     */
  1167. X
  1168. X    int old_umask, i, new_mode, new_owner, new_group, ret_code;
  1169. X
  1170. X
  1171. X    new_mode = 0600;
  1172. X    new_owner = userid;
  1173. X    new_group = groupid;
  1174. X    ret_code = 0;
  1175. X
  1176. X    if(strcmp(fname, saved_fname) == 0) {
  1177. X      new_mode = saved_buf.st_mode;
  1178. X      new_owner = saved_buf.st_uid;
  1179. X      new_group = saved_buf.st_gid;
  1180. X      ret_code = 1;
  1181. X    }
  1182. X    dprint(2, (debugfile, "** %s file stats for %s **\n",
  1183. X      (ret_code ? "restoring" : "setting"), fname));
  1184. X
  1185. X    old_umask = umask(0);
  1186. X    if((i = chmod(fname, new_mode & 0777)) == -1)
  1187. X      ret_code = -1;
  1188. X
  1189. X    dprint(2, (debugfile, "** chmod(%s, %.3o) returns %d [errno=%d] **\n",
  1190. X        fname, new_mode & 0777, i, errno));
  1191. X
  1192. X    (void) umask(old_umask);
  1193. X
  1194. X#ifdef    BSD
  1195. X    /*
  1196. X     * Chown is restricted to root on BSD unix
  1197. X     */
  1198. X    (void) chown(fname, new_owner, new_group);
  1199. X#else
  1200. X    if((i = chown(fname, new_owner, new_group)) == -1)
  1201. X      ret_code = -1;
  1202. X
  1203. X    dprint(2, (debugfile, "** chown(%s, %d, %d) returns %d [errno=%d] **\n",
  1204. X           fname, new_owner, new_group, i, errno));
  1205. X#endif
  1206. X
  1207. X    return(ret_code);
  1208. X
  1209. X}
  1210. X
  1211. X/** and finally, here's something for that evil trick: site hiding **/
  1212. X
  1213. X#ifdef SITE_HIDING
  1214. X
  1215. Xint
  1216. Xis_a_hidden_user(specific_username)
  1217. Xchar *specific_username;
  1218. X{
  1219. X    /** Returns true iff the username is present in the list of
  1220. X       'hidden users' on the system.
  1221. X    **/
  1222. X    
  1223. X    FILE *hidden_users;
  1224. X    char  buffer[SLEN];
  1225. X
  1226. X        /* 
  1227. X    this line is deliberately inserted to ensure that you THINK
  1228. X    about what you're doing, and perhaps even contact the author
  1229. X    of Elm before you USE this option...
  1230. X        */
  1231. X
  1232. X    if ((hidden_users = fopen (HIDDEN_SITE_USERS,"r")) == NULL) {
  1233. X      dprint(1, (debugfile,
  1234. X          "Couldn't open hidden site file %s [%s]\n",
  1235. X          HIDDEN_SITE_USERS, error_name(errno)));
  1236. X      return(FALSE);
  1237. X    }
  1238. X
  1239. X    while (fscanf(hidden_users, "%s", buffer) != EOF)
  1240. X      if (strcmp(buffer, specific_username) == 0) {
  1241. X        dprint(3, (debugfile, "** Found user '%s' in hidden site file!\n",
  1242. X            specific_username));
  1243. X        fclose(hidden_users);
  1244. X        return(TRUE);
  1245. X      }
  1246. X
  1247. X    fclose(hidden_users);
  1248. X    dprint(3, (debugfile, 
  1249. X        "** Couldn't find user '%s' in hidden site file!\n",
  1250. X        specific_username));
  1251. X
  1252. X    return(FALSE);
  1253. X}
  1254. X
  1255. X#endif
  1256. SHAR_EOF
  1257. chmod 0444 src/fileio.c || echo "restore of src/fileio.c fails"
  1258. echo "x - extracting src/forms.c (Text)"
  1259. sed 's/^X//' << 'SHAR_EOF' > src/forms.c &&
  1260. X
  1261. Xstatic char rcsid[] = "@(#)$Id: forms.c,v 4.1 90/04/28 22:43:08 syd Exp $";
  1262. X
  1263. X/*******************************************************************************
  1264. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1265. X *
  1266. X *             Copyright (c) 1986, 1987 Dave Taylor
  1267. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1268. X *******************************************************************************
  1269. X * Bug reports, patches, comments, suggestions should be sent to:
  1270. X *
  1271. X *    Syd Weinstein, Elm Coordinator
  1272. X *    elm@DSI.COM            dsinc!elm
  1273. X *
  1274. X *******************************************************************************
  1275. X * $Log:    forms.c,v $
  1276. X * Revision 4.1  90/04/28  22:43:08  syd
  1277. X * checkin of Elm 2.3 as of Release PL0
  1278. X * 
  1279. X *
  1280. X ******************************************************************************/
  1281. X
  1282. X/** This set of files supports the 'forms' options (AT&T Mail Forms) to
  1283. X    the mail system.  The specs are drawn from a document from AT&T entitled
  1284. X    "Standard for Exchanging Forms on AT&T Mail", version 1.9.
  1285. X
  1286. X**/
  1287. X
  1288. X/** Some notes on the format of a FORM;
  1289. X
  1290. X    First off, in AT&T Mail parlance, this program only supports SIMPLE
  1291. X    forms, currently.  This means that while each form must have three
  1292. X     sections;
  1293. X
  1294. X        [options-section]
  1295. X        ***
  1296. X        [form-image]
  1297. X        ***
  1298. X        [rules-section]
  1299. X
  1300. X    this program will ignore the first and third sections completely.  The
  1301. X    program will assume that the user merely enteres the form-image section,
  1302. X    and will append and prepend the triple asterisk sequences that *MUST*
  1303. X    be part of the message.  The messages are also expected to have a 
  1304. X    specific header - "Content-Type: mailform" - which will be added on all
  1305. X    outbound mail and checked on inbound...
  1306. X**/
  1307. X
  1308. X#include "headers.h"
  1309. X#include <errno.h>
  1310. X
  1311. Xextern int errno;
  1312. X
  1313. Xchar *error_name(), *strcat(), *strcpy();
  1314. X
  1315. Xcheck_form_file(filename)
  1316. Xchar *filename;
  1317. X{
  1318. X    /** This routine returns the number of fields in the specified file,
  1319. X        or -1 if an error is encountered. **/
  1320. X
  1321. X    FILE *form;
  1322. X    char buffer[SLEN];
  1323. X    register int field_count = 0;
  1324. X
  1325. X    if ((form = fopen(filename, "r")) == NULL) {
  1326. X      error2("Error %s trying to open %s to check fields!",
  1327. X          error_name(errno), filename);
  1328. X      return(-1);
  1329. X    }
  1330. X    
  1331. X    while (fgets(buffer, SLEN, form) != NULL) {
  1332. X      field_count += occurances_of(COLON, buffer);
  1333. X    }
  1334. X
  1335. X    fclose(form);
  1336. X
  1337. X    return(field_count);
  1338. X}
  1339. X
  1340. Xformat_form(filename)
  1341. Xchar *filename;
  1342. X{
  1343. X    /** This routine accepts a validated file that is the middle 
  1344. X        section of a form message and prepends and appends the appropriate 
  1345. X        instructions.  It's pretty simple. 
  1346. X        This returns the number of forms in the file, or -1 on errors
  1347. X    **/
  1348. X    
  1349. X    FILE *form, *newform;
  1350. X    char  newfname[SLEN], buffer[SLEN];
  1351. X    register form_count = 0;
  1352. X
  1353. X    dprint(4, (debugfile, "Formatting form file '%s'\n", filename));
  1354. X
  1355. X    /** first off, let's open the files... **/
  1356. X
  1357. X    if ((form = fopen(filename, "r")) == NULL) {
  1358. X      error("Can't read the message to validate the form!");
  1359. X      dprint(1, (debugfile,
  1360. X              "** Error encountered opening file \"%s\" - %s (check_form) **\n",
  1361. X          filename, error_name(errno)));
  1362. X      return(-1);
  1363. X    }
  1364. X
  1365. X    sprintf(newfname, "%s%s%d", temp_dir, temp_form_file, getpid());
  1366. X
  1367. X    if ((newform = fopen(newfname, "w")) == NULL) {
  1368. X      error("Couldn't open newform file for form output!");
  1369. X      dprint(1, (debugfile, 
  1370. X              "** Error encountered opening file \"%s\" - %s (check_form) **\n",
  1371. X          newfname, error_name(errno)));
  1372. X      return(-1);
  1373. X    }
  1374. X
  1375. X    /** the required header... **/
  1376. X
  1377. X    /* these are actually the defaults, but let's be sure, okay? */
  1378. X
  1379. X    fprintf(newform, "WIDTH=78\nTYPE=SIMPLE\nOUTPUT=TEXT\n***\n");
  1380. X
  1381. X    /** and let's have some fun transfering the stuff across... **/
  1382. X
  1383. X    while (fgets(buffer, SLEN, form) != NULL) {
  1384. X      fputs(buffer, newform);
  1385. X      form_count += occurances_of(COLON, buffer);
  1386. X    }
  1387. X
  1388. X    fprintf(newform, "***\n");    /* that closing bit! */
  1389. X
  1390. X    fclose(form);
  1391. X    fclose(newform);
  1392. X
  1393. X    if (form_count > 0) {
  1394. X      if (unlink(filename) != 0) {
  1395. X        error2("Error %s unlinking file %s.", error_name(errno), filename);
  1396. X        return(-1);
  1397. X      }
  1398. X      if (link(newfname, filename)) {
  1399. X        error3("Error %s linking %s to %s.", error_name(errno), 
  1400. X            newfname, filename);
  1401. X        return(-1);
  1402. X      }
  1403. X    }
  1404. X
  1405. X    if (unlink(newfname)) {
  1406. X      error2("Error %s unlinking file %s.", error_name(errno), newfname);
  1407. X      return(-1);    
  1408. X    }
  1409. X
  1410. X    return(form_count);
  1411. X}
  1412. X
  1413. Xint
  1414. Xmail_filled_in_form(address, subject)
  1415. Xchar *address, *subject;
  1416. X{
  1417. X    /** This is the interesting routine.  This one will read the
  1418. X        message and prompt the user, line by line, for each of
  1419. X        the fields...returns non-zero if it succeeds
  1420. X    **/
  1421. X
  1422. X    FILE           *fd;
  1423. X    register int lines = 0, count;
  1424. X    char         buffer[SLEN], *ptr;
  1425. X
  1426. X    dprint(4, (debugfile, 
  1427. X        "replying to form with;\n\taddress=%s and\n\t subject=%s\n",
  1428. X         address, subject));
  1429. X
  1430. X        if (fseek(mailfile, headers[current-1]->offset, 0) == -1) {
  1431. X      dprint(1, (debugfile,
  1432. X           "Error: seek %ld resulted in errno %s (%s)\n", 
  1433. X           headers[current-1]->offset, error_name(errno), 
  1434. X           "mail_filled_in_form"));
  1435. X      error2("ELM [seek] couldn't read %d bytes into file (%s).",
  1436. X             headers[current-1]->offset, error_name(errno));
  1437. X      return(0);
  1438. X        }
  1439. X    /* now we can fly along and get to the message body... */
  1440. X
  1441. X    while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
  1442. X      if (strlen(buffer) == 1)    /* <return> only */
  1443. X        break;
  1444. X      else if (strncmp(buffer,"From ", 5) == 0 && lines++ > 0) {
  1445. X        error("No form in this message!?");
  1446. X        return(0);
  1447. X      }
  1448. X    }
  1449. X
  1450. X    if (ptr == NULL) {
  1451. X      error("No form in this message!?");
  1452. X      return(0);
  1453. X    }
  1454. X
  1455. X    dprint(6, (debugfile, "- past header of form message -\n"));
  1456. X    
  1457. X    /* at this point we're at the beginning of the body of the message */
  1458. X
  1459. X    /* now we can skip to the FORM-IMAGE section by reading through a 
  1460. X       line with a triple asterisk... */
  1461. X
  1462. X    while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
  1463. X      if (strcmp(buffer, "***\n") == 0)
  1464. X        break;    /* we GOT it!  It's a miracle! */    
  1465. X      else if (strncmp(buffer, "From ",5) == 0) {
  1466. X        error("Badly constructed form.  Can't reply!");
  1467. X        return(0);
  1468. X      }
  1469. X    }
  1470. X
  1471. X    if (ptr == NULL) {
  1472. X      error("Badly constructed form.  Can't reply!");
  1473. X      return(0);
  1474. X    }
  1475. X
  1476. X    dprint(6, (debugfile, "- skipped the non-forms-image stuff -\n"));
  1477. X    
  1478. X    /* one last thing - let's open the tempfile for output... */
  1479. X    
  1480. X    sprintf(buffer, "%s%s%d", temp_dir, temp_form_file, getpid());
  1481. X
  1482. X    dprint(2, (debugfile,"-- forms sending using file %s --\n", buffer));
  1483. X
  1484. X    if ((fd = fopen(buffer,"w")) == NULL) {
  1485. X      error2("Can't open \"%s\" as output file! (%s).", buffer,
  1486. X         error_name(errno));
  1487. X      dprint(1, (debugfile,
  1488. X          "** Error %s encountered trying to open temp file %s;\n",
  1489. X          error_name(errno), buffer));
  1490. X      return(0);
  1491. X    }
  1492. X
  1493. X    /* NOW we're ready to read the form image in and start prompting... */
  1494. X
  1495. X    Raw(OFF);
  1496. X    ClearScreen();
  1497. X
  1498. X    while ((ptr = fgets(buffer, SLEN, mailfile)) != NULL) {
  1499. X      dprint(9, (debugfile, "- read %s", buffer));
  1500. X      if (strcmp(buffer, "***\n") == 0) /* end of form! */
  1501. X        break;
  1502. X     
  1503. X      switch ((count = occurances_of(COLON, buffer))) {
  1504. X        case 0 : printf("%s", buffer);        /* output line */
  1505. X             fprintf(fd, "%s", buffer);     
  1506. X             break;
  1507. X            case 1 : if (buffer[0] == COLON) {
  1508. X                   printf(
  1509. X"(Enter as many lines as needed, ending with a '.' by itself on a line)\n");
  1510. X                       while (fgets(buffer, SLEN, stdin) != NULL) {
  1511. X                 no_ret(buffer);
  1512. X                     if (strcmp(buffer, ".") == 0)
  1513. X                       break;
  1514. X                     else 
  1515. X               fprintf(fd,"%s\n", buffer);
  1516. X               }
  1517. X                 }
  1518. X                 else 
  1519. X               prompt_for_entries(buffer, fd, count);
  1520. X                 break;
  1521. X            default: prompt_for_entries(buffer, fd, count);
  1522. X      }
  1523. X    }
  1524. X
  1525. X    Raw(ON);
  1526. X    fclose(fd);
  1527. X
  1528. X    /** let's just mail this off now... **/
  1529. X
  1530. X    mail_form(address, subject);
  1531. X
  1532. X    return(1);
  1533. X}
  1534. X
  1535. Xprompt_for_entries(buffer, fd, entries)
  1536. Xchar *buffer;
  1537. XFILE *fd;
  1538. Xint  entries;
  1539. X{
  1540. X    /** deals with lines that have multiple colons on them.  It must first
  1541. X        figure out how many spaces to allocate for each field then prompts
  1542. X        the user, line by line, for the entries...
  1543. X    **/
  1544. X
  1545. X    char mybuffer[SLEN], prompt[SLEN], spaces[SLEN];
  1546. X    register int  field_size, i, j, offset = 0, extra_tabs = 0;
  1547. X
  1548. X    dprint(7, (debugfile, 
  1549. X        "prompt-for-multiple [%d] -entries \"%s\"\n", entries,
  1550. X        buffer));
  1551. X
  1552. X    strcpy(prompt, "No Prompt Available:");
  1553. X
  1554. X    while (entries--) {
  1555. X      j=0; 
  1556. X      i = chloc((char *) buffer + offset, COLON) + 1;
  1557. X      while (j < i - 1) {
  1558. X        prompt[j] = buffer[j+offset];
  1559. X        j++;
  1560. X      }
  1561. X      prompt[j] = '\0';
  1562. X
  1563. X      field_size = 0;
  1564. X
  1565. X      while (whitespace(buffer[i+offset])) {
  1566. X        if (buffer[i+offset] == TAB) {
  1567. X          field_size += 8 - (i % 8);
  1568. X          extra_tabs += (8 - (i % 8)) - 1;
  1569. X        }
  1570. X        else
  1571. X          field_size += 1;
  1572. X        i++;
  1573. X      }
  1574. X
  1575. X      offset += i;
  1576. X    
  1577. X      if (field_size == 0)     /* probably last prompt in line... */
  1578. X        field_size = 78 - (offset + extra_tabs);
  1579. X
  1580. X      prompt_for_sized_entry(prompt, mybuffer, field_size);
  1581. X
  1582. X      spaces[0] = ' ';    /* always at least ONE trailing space... */
  1583. X      spaces[1] = '\0';
  1584. X
  1585. X      /*  field_size-1 for the space spaces[] starts with  */
  1586. X      for (j = strlen(mybuffer); j < field_size-1; j++)
  1587. X        strcat(spaces, " ");
  1588. X
  1589. X      fprintf(fd, "%s: %s%s", prompt, mybuffer, spaces);
  1590. X      fflush(fd);
  1591. X    }
  1592. X
  1593. X    fprintf(fd, "\n");
  1594. X}
  1595. X
  1596. Xprompt_for_sized_entry(prompt, buffer, field_size)
  1597. Xchar *prompt, *buffer;
  1598. Xint   field_size;
  1599. X{
  1600. X    /* This routine prompts for an entry of the size specified. */
  1601. X
  1602. X    register int i;
  1603. X
  1604. X    dprint(7, (debugfile, "prompt-for-sized-entry \"%s\" %d chars\n", 
  1605. X        prompt, field_size));
  1606. X
  1607. X    printf("%s: ", prompt);
  1608. X    
  1609. X    for (i=0;i<field_size; i++)
  1610. X      putchar('_');
  1611. X    for (i=0;i<field_size; i++)
  1612. X      putchar(BACKSPACE);
  1613. X    fflush(stdout);
  1614. X
  1615. X    fgets(buffer, SLEN, stdin);
  1616. X    no_ret(buffer);
  1617. X
  1618. X    if (strlen(buffer) > field_size) buffer[field_size-1] = '\0';
  1619. X}
  1620. SHAR_EOF
  1621. chmod 0444 src/forms.c || echo "restore of src/forms.c fails"
  1622. echo "x - extracting src/hdrconfg.c (Text)"
  1623. sed 's/^X//' << 'SHAR_EOF' > src/hdrconfg.c &&
  1624. X
  1625. Xstatic char rcsid[] = "@(#)$Id: hdrconfg.c,v 4.1 90/04/28 22:43:10 syd Exp $";
  1626. X
  1627. X/*******************************************************************************
  1628. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1629. X *
  1630. X *             Copyright (c) 1986, 1987 Dave Taylor
  1631. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1632. X *******************************************************************************
  1633. X * Bug reports, patches, comments, suggestions should be sent to:
  1634. X *
  1635. X *    Syd Weinstein, Elm Coordinator
  1636. X *    elm@DSI.COM            dsinc!elm
  1637. X *
  1638. X *******************************************************************************
  1639. X * $Log:    hdrconfg.c,v $
  1640. X * Revision 4.1  90/04/28  22:43:10  syd
  1641. X * checkin of Elm 2.3 as of Release PL0
  1642. X * 
  1643. X *
  1644. X ******************************************************************************/
  1645. X
  1646. X/**   This file contains the routines necessary to be able to modify
  1647. X      the mail headers of messages on the way off the machine.  The
  1648. X      headers currently supported for modification are:
  1649. X
  1650. X    Subject:
  1651. X    To:
  1652. X    Cc:
  1653. X    Bcc:
  1654. X    Reply-To:
  1655. X    Expires:
  1656. X    Priority:
  1657. X        In-Reply-To:
  1658. X    Action:
  1659. X
  1660. X    <user defined>
  1661. X**/
  1662. X
  1663. X#include "headers.h"
  1664. X
  1665. X#include <ctype.h>
  1666. X
  1667. X#ifdef BSD
  1668. X#undef toupper
  1669. X#undef tolower
  1670. X#endif
  1671. X
  1672. X/*
  1673. X * Allow three lines for To and Cc.
  1674. X * Allow two lines for Bcc, Subject and In-reply-to.
  1675. X * Allow one line for all others.
  1676. X */
  1677. X#define TO_LINE            2
  1678. X#define CC_LINE                 5
  1679. X#define BCC_LINE                8
  1680. X#define SUBJECT_LINE            10
  1681. X#define REPLY_TO_LINE           12
  1682. X#define ACTION_LINE             13
  1683. X#define EXPIRES_LINE            14
  1684. X#define PRIORITY_LINE           15
  1685. X#define IN_REPLY_TO_LINE        16
  1686. X#define USER_DEFINED_HDR_LINE   18
  1687. X#define INSTRUCT_LINE           LINES-4
  1688. X#define EXTRA_PROMPT_LINE    LINES-3
  1689. X#define INPUT_LINE        LINES-2
  1690. X#define ERROR_LINE        LINES-1
  1691. X
  1692. Xstatic  put_header();
  1693. X
  1694. X#define put_to()        put_header(TO_LINE, 3, "To", expanded_to)
  1695. X#define put_cc()        put_header(CC_LINE, 3, "Cc", expanded_cc)
  1696. X#define put_bcc()       put_header(BCC_LINE, 2, "Bcc", expanded_bcc)
  1697. X#define put_subject()   put_header(SUBJECT_LINE, 2, "Subject", subject)
  1698. X#define put_replyto()   put_header(REPLY_TO_LINE, 1, "Reply-to", reply_to)
  1699. X#define put_action()    put_header(ACTION_LINE, 1, "Action", action)
  1700. X#define put_expires()   put_header(EXPIRES_LINE, 1, "Expires", expires)
  1701. X#define put_priority()  put_header(PRIORITY_LINE, 1, "Priority", priority)
  1702. X#define put_inreplyto() put_header(IN_REPLY_TO_LINE, 2, \
  1703. X                    "In-reply-to", in_reply_to)
  1704. X#define put_userdefined() put_header(USER_DEFINED_HDR_LINE, 1, \
  1705. X                    (char *) NULL, user_defined_header)
  1706. X
  1707. X/* these are all defined in the mailmsg file! */
  1708. Xextern char subject[SLEN], in_reply_to[SLEN], expires[SLEN], 
  1709. X            action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], 
  1710. X        cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], 
  1711. X        expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
  1712. X        bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
  1713. X
  1714. Xchar *strip_commas(), *strcpy();
  1715. X
  1716. Xedit_headers()
  1717. X{
  1718. X    /** Edit headers.  **/
  1719. X    int c, displayed_error = NO;
  1720. X
  1721. X    /*  Expand address-type headers for main part of display */
  1722. X    /*  (Unexpanded ones are used on the 'edit-line') */
  1723. X    (void) build_address(strip_commas(to), expanded_to);
  1724. X    (void) build_address(strip_commas(cc), expanded_cc);
  1725. X    (void) build_address(strip_commas(bcc), expanded_bcc);
  1726. X    
  1727. X    display_headers();
  1728. X
  1729. X    clearerr(stdin);
  1730. X
  1731. X    while (TRUE) {    /* forever */
  1732. X      PutLine0(INPUT_LINE,0,"Choice: ");
  1733. X      if (displayed_error)
  1734. X        displayed_error = NO;
  1735. X      else
  1736. X        CleartoEOS();
  1737. X      c = getchar();
  1738. X      if (isupper(c))
  1739. X        c = tolower(c);
  1740. X      clear_error();
  1741. X      if (c == EOF)
  1742. X        return(0);
  1743. X      switch (c) {
  1744. X        case RETURN:
  1745. X        case LINE_FEED:
  1746. X        case 'q' :  MoveCursor(INSTRUCT_LINE, 0);
  1747. X            CleartoEOS();
  1748. X            return(0);
  1749. X
  1750. X        case ctrl('L') :
  1751. X            display_headers();
  1752. X            break;
  1753. X
  1754. X        case 't' :  PutLine0(INPUT_LINE, 0, "To: "); CleartoEOLN();
  1755. X                     if (optionally_enter(to, INPUT_LINE, 4, TRUE, FALSE) == -1)
  1756. X              return(0);
  1757. X            (void) build_address(strip_commas(to), expanded_to);
  1758. X            put_to();
  1759. X            break;
  1760. X
  1761. X        case 's' :  PutLine0(INPUT_LINE, 0, "Subject: "); CleartoEOLN();
  1762. X                if (optionally_enter(subject,
  1763. X                  INPUT_LINE, 9, FALSE, FALSE) == -1)
  1764. X              return(0);
  1765. X            put_subject();
  1766. X            break;
  1767. X
  1768. X        case 'b' :  PutLine0(INPUT_LINE, 0, "Bcc: "); CleartoEOLN();
  1769. X                if (optionally_enter(bcc,
  1770. X                  INPUT_LINE, 5, TRUE, FALSE) == -1)
  1771. X              return(0);
  1772. X            (void) build_address(strip_commas(bcc), expanded_bcc);
  1773. X            put_bcc();
  1774. X            break;
  1775. X
  1776. X        case 'c' :  PutLine0(INPUT_LINE, 0, "Cc: "); CleartoEOLN();
  1777. X                if (optionally_enter(cc, INPUT_LINE, 4, TRUE, FALSE) == -1)
  1778. X              return(0);
  1779. SHAR_EOF
  1780. echo "End of part 15"
  1781. echo "File src/hdrconfg.c is continued in part 16"
  1782. echo "16" > s2_seq_.tmp
  1783. exit 0
  1784.  
  1785. exit 0 # Just in case...
  1786.