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

  1. Subject:  v22i076:  ELM mail syste, release 2.3, Part17/26
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: be6ab14a 542cdba5 7368fbd2 f3129d3b
  5.  
  6. Submitted-by: Syd Weinstein <syd@dsinc.dsi.com>
  7. Posting-number: Volume 22, Issue 76
  8. Archive-name: elm2.3/part17
  9.  
  10. ---- Cut Here and unpack ----
  11. #!/bin/sh
  12. # this is part 17 of a multipart archive
  13. # do not concatenate these parts, unpack them in order with /bin/sh
  14. # file src/leavembox.c continued
  15. #
  16. CurArch=17
  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/leavembox.c"
  27. sed 's/^X//' << 'SHAR_EOF' >> src/leavembox.c
  28. X     */
  29. X
  30. X    for (num_chgd_status = 0, i = 0; i < message_count; i++)
  31. X      if(headers[i]->status_chgd == TRUE)
  32. X        num_chgd_status++;
  33. X    
  34. X    if(!to_delete && !to_store && !num_chgd_status && !resyncing) {
  35. X      dprint(3, (debugfile, "Folder keep as is!\n"));
  36. X      error("Folder unchanged.");
  37. X      return(0);
  38. X    }
  39. X
  40. X    /** we have to check to see what the sorting order was...so that
  41. X        the order in which we write messages is the same as the order
  42. X        of the messages originally.
  43. X        We only need to do this if there are any messages to be
  44. X        written out (either to keep or to store). **/
  45. X
  46. X    if ((to_keep || to_store ) && sortby != MAILBOX_ORDER) {
  47. X      last_sortby = sortby;
  48. X      sortby = MAILBOX_ORDER;
  49. X      sort_mailbox(message_count, FALSE);
  50. X      sortby = last_sortby;
  51. X    }
  52. X
  53. X    /* Formulate message as to number of keeps, stores, and deletes.
  54. X     * This is only complex so that the message is good English.
  55. X     */
  56. X    if (to_keep > 0) {
  57. X      if (to_store > 0) {
  58. X        if (to_delete > 0)
  59. X          sprintf(buffer,
  60. X                "[Keeping %d message%s, storing %d, and deleting %d.]", 
  61. X            to_keep, plural(to_keep), to_store, to_delete);
  62. X        else
  63. X          sprintf(buffer, "[Keeping %d message%s and storing %d.]", 
  64. X            to_keep, plural(to_keep), to_store);
  65. X      } else {
  66. X        if (to_delete > 0)
  67. X          sprintf(buffer, "[Keeping %d message%s and deleting %d.]", 
  68. X            to_keep, plural(to_keep), to_delete);
  69. X        else
  70. X          sprintf(buffer, "[Keeping %s.]",
  71. X            to_keep > 1 ? "all messages" : "message");
  72. X      }
  73. X    } else if (to_store > 0) {
  74. X      if (to_delete > 0)
  75. X        sprintf(buffer, "[Storing %d message%s and deleting %d.]", 
  76. X          to_store, plural(to_store), to_delete);
  77. X      else 
  78. X        sprintf(buffer, "[Storing %s.]",
  79. X          to_store > 1? "all messages" : "message");
  80. X
  81. X    } else {
  82. X      if (to_delete > 0)
  83. X        sprintf(buffer, "[Deleting all messages.]");
  84. X      else
  85. X        buffer[0] = '\0';
  86. X    }
  87. X    /* NOTE: don't use variable "buffer" till message is output later */
  88. X
  89. X    /** next, let's lock the file up and make one last size check **/
  90. X
  91. X    if (folder_type == SPOOL)
  92. X      lock(OUTGOING);
  93. X    
  94. X    if (mailfile_size != bytes(cur_folder)) {
  95. X      unlock();
  96. X      error("New mail has just arrived. Resynchronizing...");
  97. X      return(-1);
  98. X    }
  99. X    
  100. X    /* Everything's GO - so ouput that user message and go to it. */
  101. X
  102. X    dprint(2, (debugfile, "Action: %s\n", buffer));
  103. X    error(buffer);
  104. X
  105. X    /* Store messages slated for storage in received mail folder */
  106. X    if (to_store > 0) {
  107. X      if ((errno = can_open(recvd_mail, "a"))) {
  108. X        error1(
  109. X          "Permission to append to %s denied!  Leaving folder intact.\n",
  110. X          recvd_mail);
  111. X        dprint(1, (debugfile,
  112. X          "Error: Permission to append to folder %s denied!! (%s)\n",
  113. X          recvd_mail, "leavembox"));
  114. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  115. X          error_description(errno)));
  116. X        unlock();
  117. X        return(0);
  118. X      }
  119. X      if ((temp = fopen(recvd_mail,"a")) == NULL) {
  120. X        unlock();
  121. X        dprint(1, (debugfile, "Error: could not append to file %s\n", 
  122. X          recvd_mail));
  123. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  124. X          error_description(errno)));
  125. X        sprintf(buffer, "Could not append to folder %s!", recvd_mail);
  126. X        Centerline(LINES-1, buffer);
  127. X        emergency_exit();
  128. X      }
  129. X      dprint(2, (debugfile, "Storing message%s ", plural(to_store)));
  130. X      for (i = 0; i < message_count; i++) {
  131. X        if(headers[i]->exit_disposition == STORE) {
  132. X          current = i+1;
  133. X          dprint(2, (debugfile, "#%d, ", current));
  134. X          copy_message("", temp, FALSE, FALSE, TRUE, FALSE);
  135. X        }
  136. X      }
  137. X      fclose(temp);
  138. X      dprint(2, (debugfile, "\n\n"));
  139. X      chown(recvd_mail, userid, groupid);
  140. X    }
  141. X
  142. X    /* If there are any messages to keep, first copy them to a
  143. X     * temp file, then remove original and copy whole temp file over.
  144. X     */
  145. X    if (to_keep > 0) {
  146. X      sprintf(temp_keep_file, "%s%s%d", temp_dir, temp_file, getpid());
  147. X      if ((errno = can_open(temp_keep_file, "w"))) {
  148. X        error1(
  149. X"Permission to create temp file %s for writing denied! Leaving folder intact.",
  150. X          temp_keep_file);
  151. X        dprint(1, (debugfile,
  152. X          "Error: Permission to create temp file %s denied!! (%s)\n",
  153. X          temp_keep_file, "leavembox"));
  154. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  155. X          error_description(errno)));
  156. X        unlock();
  157. X        return(0);
  158. X      }
  159. X      if ((temp = fopen(temp_keep_file,"w")) == NULL) {
  160. X        unlock();
  161. X        dprint(1, (debugfile, "Error: could not create file %s\n", 
  162. X          temp_keep_file));
  163. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  164. X          error_description(errno)));
  165. X        sprintf(buffer, "Could not create temp file %s!", temp_keep_file);
  166. X        Centerline(LINES-1, buffer);
  167. X        emergency_exit();
  168. X      }
  169. X      dprint(2, (debugfile, "Copying to temp file message%s to be kept ",
  170. X        plural(to_keep)));
  171. X      for (i = 0; i < message_count; i++) {
  172. X        if(headers[i]->exit_disposition == KEEP) {
  173. X          current = i+1;
  174. X          dprint(2, (debugfile, "#%d, ", current));
  175. X          copy_message("", temp, FALSE, FALSE, TRUE, FALSE);
  176. X        }
  177. X      }
  178. X      if ( fclose(temp) == EOF ) {
  179. X        Write_to_screen("\n\rClose failed on temp keep file in leavembox\n\r", 0);
  180. X        perror(temp_keep_file);
  181. X        dprint(2, (debugfile, "\n\rfclose err on temp_keep_file - leavembox\n\r"));
  182. X        rm_temps_exit();
  183. X      }
  184. X      dprint(2, (debugfile, "\n\n"));
  185. X
  186. X    } else if (folder_type == NON_SPOOL && !keep_empty_files) {
  187. X
  188. X      /* i.e. if no messages were to be kept and this is not a spool
  189. X       * folder and we aren't keeping empty non-spool folders,
  190. X       * simply remove the old original folder and that's it!
  191. X       */
  192. X      (void)unlink(cur_folder);
  193. X      return(1);
  194. X    }
  195. X
  196. X    /* Otherwise we have some work left to do! */
  197. X
  198. X    /* Get original permissions and access time of the original
  199. X     * mail folder before we remove it.
  200. X     */
  201. X    if(save_file_stats(cur_folder) != 0) {
  202. X      error1("Problems saving permissions of folder %s!", cur_folder);
  203. X      sleep(2);
  204. X    }
  205. X      
  206. X        if (stat(cur_folder, &buf) != 0) {
  207. X      dprint(1, (debugfile, "Error: errno %s attempting to stat file %s\n", 
  208. X             error_name(errno), cur_folder));
  209. X          error3("Error %s (%s) on stat(%s).", error_name(errno), 
  210. X        error_description(errno), cur_folder);
  211. X    }
  212. X
  213. X    /* Close and remove the original folder.
  214. X     * However, if we are going to copy a temp file of kept messages
  215. X     * to it, and this is a locked (spool) mailbox, we need to keep
  216. X     * it locked during this process. Unfortunately,
  217. X     * if we did our LOCK_BY_FLOCK, unlinking the original will kill the
  218. X     * lock, so we have to resort to copying the temp file to the original
  219. X     * file while keeping the original open.
  220. X     * Also, if the file has a link count > 1, then it has links, so to
  221. X     * prevent destroying the links, we do a copy back, even though its
  222. X     * slower.
  223. X     */
  224. X
  225. X    fclose(mailfile);
  226. X
  227. X    if(to_keep) {
  228. X#ifdef LOCK_BY_FLOCK
  229. X      need_to_copy = (folder_type == SPOOL ? TRUE : FALSE);
  230. X#else
  231. X      need_to_copy = FALSE;
  232. X#endif
  233. X      if (buf.st_nlink > 1)
  234. X        need_to_copy = TRUE;
  235. X
  236. X      if(!need_to_copy) {
  237. X        unlink(cur_folder);
  238. X        if (link(temp_keep_file, cur_folder) != 0) {
  239. X          if(errno == EXDEV || errno == EEXIST) {
  240. X        /* oops - can't link across file systems - use copy instead */
  241. X        need_to_copy = TRUE;
  242. X          } else {
  243. X        dprint(1, (debugfile, "link(%s, %s) failed (leavembox)\n", 
  244. X               temp_keep_file, cur_folder));
  245. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  246. X              error_description(errno)));
  247. X        error2("Link failed! %s - %s.", error_name(errno),
  248. X          error_description(errno));
  249. X        unlock();
  250. X        emergency_exit();
  251. X          }
  252. X        }
  253. X      }
  254. X
  255. X      if(need_to_copy) {
  256. X
  257. X        if (copy(temp_keep_file, cur_folder) != 0) {
  258. X
  259. X          /* copy to cur_folder failed - try to copy to special file */
  260. X          dprint(1, (debugfile, "leavembox: copy(%s, %s) failed;",
  261. X              temp_keep_file, cur_folder));
  262. X          dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  263. X           error_description(errno)));
  264. X          error("Couldn't modify folder!");
  265. X          sleep(1);
  266. X          sprintf(cur_folder,"%s/%s", home, unedited_mail);
  267. X          if (copy(temp_keep_file, cur_folder) != 0) {
  268. X
  269. X        /* couldn't copy to special file either */
  270. X        dprint(1, (debugfile, 
  271. X            "leavembox: couldn't copy to %s either!!  Help;", 
  272. X            cur_folder));
  273. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  274. X            error_description(errno)));
  275. X        error("Can't copy mailbox, system trouble!!!");
  276. X        unlock();
  277. X        emergency_exit();
  278. X          } else {
  279. X        dprint(1, (debugfile,
  280. X            "\nWoah! Confused - Saved mail in %s (leavembox)\n", 
  281. X            cur_folder));
  282. X        error1("Saved mail in %s.", cur_folder);
  283. X        sleep(1);
  284. X          }
  285. X        }
  286. X      }
  287. X
  288. X      /* link or copy complete - remove temp keep file */
  289. X      unlink(temp_keep_file);
  290. X
  291. X    } else if(folder_type == SPOOL || keep_empty_files) {
  292. X
  293. X      /* if this is an empty spool file, or if this is an empty non spool 
  294. X       * file and we keep empty non spool files (we always keep empty
  295. X       * spool files), create an empty file */
  296. X
  297. X      if(folder_type == NON_SPOOL)
  298. X        error1("Keeping empty folder '%s'.", cur_folder);
  299. X      temp = fopen(cur_folder, "w");
  300. X      fclose(temp);
  301. X    }
  302. X
  303. X    /* restore permissions and access times of folder */
  304. X
  305. X    if(restore_file_stats(cur_folder) != 1) {
  306. X      error1("Problems restoring permissions of folder %s!", cur_folder);
  307. X      sleep(2);
  308. X    }
  309. X
  310. X#ifdef BSD
  311. X    utime_buffer[0]     = buf.st_atime;
  312. X    utime_buffer[1]     = buf.st_mtime;
  313. X#else
  314. X    utime_buffer.actime = buf.st_atime;
  315. X    utime_buffer.modtime= buf.st_mtime;
  316. X#endif
  317. X
  318. X#ifdef BSD
  319. X    if (utime(cur_folder, utime_buffer) != 0) {
  320. X#else
  321. X    if (utime(cur_folder, &utime_buffer) != 0) {
  322. X#endif
  323. X      dprint(1, (debugfile, 
  324. X         "Error: encountered error doing utime (leavmbox)\n"));
  325. X      dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), 
  326. X           error_description(errno)));
  327. X      error2("Error %s trying to change file %s access time.", 
  328. X           error_name(errno), cur_folder);
  329. X    }
  330. X
  331. X
  332. X    mailfile_size = bytes(cur_folder);
  333. X    unlock();    /* remove the lock on the file ASAP! */
  334. X
  335. X    return(1);    
  336. X}
  337. X
  338. Xstatic int  lock_state = OFF;
  339. X
  340. Xstatic char lock_name[SLEN];
  341. X
  342. Xchar *
  343. Xmk_lockname(file_to_lock)
  344. Xchar *file_to_lock;
  345. X{
  346. X    /** Create the proper name of the lock file for file_to_lock,
  347. X        which is presumed to be a spool file full path (see
  348. X        get_folder_type()), and put it in the static area lock_name.
  349. X        Return lock_name for informational purposes.
  350. X     **/
  351. X
  352. X#ifdef XENIX
  353. X    /* lock is /tmp/[basename of file_to_lock].mlk */
  354. X    sprintf(lock_name, "/tmp/%.10s.mlk", rindex(file_to_lock, '/')+1);
  355. X#else
  356. X    /* lock is [file_to_lock].lock */
  357. X    sprintf(lock_name, "%s.lock", file_to_lock);
  358. X#endif
  359. X    return(lock_name);
  360. X}
  361. X
  362. X
  363. Xstatic int flock_fd,    /* file descriptor for flocking mailbox itself */
  364. X       create_fd;    /* file descriptor for creating lock file */
  365. X
  366. Xlock(direction)
  367. Xint direction;
  368. X{
  369. X      /** Create lock file to ensure that we don't get any mail 
  370. X      while altering the folder contents!
  371. X      If it already exists sit and spin until 
  372. X         either the lock file is removed...indicating new mail
  373. X      or
  374. X         we have iterated MAX_ATTEMPTS times, in which case we
  375. X         either fail or remove it and make our own (determined
  376. X         by if REMOVE_AT_LAST is defined in header file
  377. X
  378. X      If direction == INCOMING then DON'T remove the lock file
  379. X      on the way out!  (It'd mess up whatever created it!).
  380. X
  381. X      But if that succeeds and if we are also locking by flock(),
  382. X      follow a similar algorithm. Now if we can't lock by flock(),
  383. X      we DO need to remove the lock file, since if we got this far,
  384. X      we DID create it, not another process.
  385. X      **/
  386. X
  387. X      register int create_iteration = 0,
  388. X           flock_iteration = 0;
  389. X      char pid_buffer[SHORT];
  390. X
  391. X#ifndef    LOCK_FLOCK_ONLY        /* { LOCK_FLOCK_ONLY    */
  392. X      /* formulate lock file name */
  393. X      mk_lockname(cur_folder);
  394. X
  395. X#ifdef PIDCHECK
  396. X      /** first, try to read the lock file, and if possible, check the pid.
  397. X      If we can validate that the pid is no longer active, then remove
  398. X      the lock file.
  399. X       **/
  400. X      if((create_fd=open(lock_name,O_RDONLY)) != -1) {
  401. X    if (read(create_fd, pid_buffer, SHORT) > 0) {
  402. X      create_iteration = atoi(pid_buffer);
  403. X      if (create_iteration) {
  404. X        if (kill(create_iteration, 0)) {
  405. X          close(create_fd);
  406. X          if (unlink(lock_name) != 0) {
  407. X        dprint(1, (debugfile,
  408. X          "Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
  409. X          error_name(errno), error_description(errno), lock_name, "lock"));
  410. X        PutLine1(LINES, 0, 
  411. X          "\n\rCouldn't remove the current lock file %s\n\r", lock_name);
  412. X        PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  413. X          error_description(errno));
  414. X        if (direction == INCOMING)
  415. X          leave();
  416. X        else
  417. X          emergency_exit();
  418. X          }
  419. X        }
  420. X      }
  421. X    }
  422. X    create_iteration = 0;
  423. X      }
  424. X#endif
  425. X          
  426. X      /* try to assert create lock file MAX_ATTEMPTS times */
  427. X      do {
  428. X
  429. X    errno = 0;
  430. X    if((create_fd=open(lock_name,O_WRONLY | O_CREAT | O_EXCL,0444)) != -1)
  431. X      break;
  432. X    else {
  433. X      if(errno != EEXIST) {
  434. X        /* Creation of lock failed NOT because it already exists!!! */
  435. X
  436. X        if (direction == OUTGOING) {
  437. X          dprint(1, (debugfile, 
  438. X        "Error encountered attempting to create lock %s\n", lock_name));
  439. X          dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  440. X            error_description(errno)));
  441. X          MoveCursor(LINES, 0);
  442. X          printf(
  443. X       "\n\rError encountered while attempting to create lock file %s;\n\r",
  444. X        lock_name);
  445. X          printf("** %s - %s.**\n\r\n\r",
  446. X        error_name(errno), error_description(errno));
  447. X        } else {    /* incoming - permission denied in the middle?  Odd. */
  448. X          dprint(1, (debugfile,
  449. X           "Can't create lock file: creat(%s) raises error %s (lock)\n", 
  450. X        lock_name, error_name(errno)));
  451. X          error1(
  452. X           "Can't create lock file! Need write permission in \"%s\".\n\r",
  453. X        mailhome);
  454. X        }
  455. X        leave();
  456. X      }
  457. X    }
  458. X    dprint(2, (debugfile,"File '%s' already exists!  Waiting...(lock)\n", 
  459. X      lock_name));
  460. X    error1(
  461. X      "Waiting to read mailbox while mail is being received: attempt #%d",
  462. X      create_iteration);
  463. X    sleep(5);
  464. X      } while (create_iteration++ < MAX_ATTEMPTS);
  465. X      clear_error();
  466. X
  467. X      if(errno != 0) {
  468. X    
  469. X    /* we weren't able to create the lock file */
  470. X
  471. X#ifdef REMOVE_AT_LAST
  472. X
  473. X    /** time to waste the lock file!  Must be there in error! **/
  474. X    dprint(2, (debugfile, 
  475. X       "Warning: I'm giving up waiting - removing lock file(lock)\n"));
  476. X    if (direction == INCOMING)
  477. X      PutLine0(LINES, 0,"\nTimed out - removing current lock file...");
  478. X    else
  479. X      error("Throwing away the current lock file!");
  480. X
  481. X    if (unlink(lock_name) != 0) {
  482. X      dprint(1, (debugfile,
  483. X        "Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
  484. X        error_name(errno), error_description(errno), lock_name, "lock"));
  485. X      PutLine1(LINES, 0, 
  486. X        "\n\rCouldn't remove the current lock file %s\n\r", lock_name);
  487. X      PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  488. X        error_description(errno));
  489. X      if (direction == INCOMING)
  490. X        leave();
  491. X      else
  492. X        emergency_exit();
  493. X    }
  494. X
  495. X    /* we've removed the bad lock, let's try to assert lock once more */
  496. X    if((create_fd=open(lock_name,O_WRONLY | O_CREAT | O_EXCL,0444)) == -1){
  497. X
  498. X      /* still can't lock it - just give up */
  499. X      dprint(1, (debugfile, 
  500. X        "Error encountered attempting to create lock %s\n", lock_name));
  501. X      dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  502. X        error_description(errno)));
  503. X      MoveCursor(LINES, 0);
  504. X      printf(
  505. X      "\n\rError encountered while attempting to create lock file %s;\n\r",
  506. X        lock_name);
  507. X      printf("** %s - %s.**\n\r\n\r", error_name(errno),
  508. X        error_description(errno));
  509. X      leave();
  510. X    }
  511. X#else
  512. X    /* Okay...we die and leave, not updating the mailfile mbox or
  513. X       any of those! */
  514. X
  515. X    if (direction == INCOMING) {
  516. X      PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations.\n\r", 
  517. X        create_iteration);
  518. X      PutLine0(LINES, 0, 
  519. X      "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
  520. X      dprint(1, (debugfile, 
  521. X        "Warning: bailing out after %d iterations...(lock)\n",
  522. X        create_iteration));
  523. X      leave_locked(0);
  524. X    } else {
  525. X      dprint(1, (debugfile, 
  526. X       "Warning: after %d iterations, timed out! (lock)\n",
  527. X       create_iteration));
  528. X      leave(error("Timed out on locking mailbox.  Leaving program."));
  529. X    }
  530. X#endif
  531. X      }
  532. X
  533. X      /* If we're here we successfully created the lock file */
  534. X      dprint(5,
  535. X    (debugfile, "Lock %s %s for file %s on.\n", lock_name,
  536. X    (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
  537. X
  538. X      /* Place the pid of Elm into the lock file for SVR3.2 and its ilk */
  539. X      sprintf(pid_buffer, "%d", getpid());
  540. X      write(create_fd, pid_buffer, strlen(pid_buffer));
  541. X
  542. X      (void)close(create_fd);
  543. X#endif                /* } LOCK_FLOCK_ONLY */
  544. X
  545. X#ifdef LOCK_BY_FLOCK
  546. X      /* Now we also need to lock the file with flock(2) */
  547. X
  548. X      /* Open mail file separately for locking */
  549. X      if((flock_fd = open(cur_folder, O_RDONLY)) < 0) {
  550. X    dprint(1, (debugfile, 
  551. X        "Error encountered attempting to reopen %s for lock\n", cur_folder));
  552. X    dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  553. X        error_description(errno)));
  554. X    MoveCursor(LINES, 0);
  555. X    printf(
  556. X "\n\rError encountered while attempting to reopen mailbox %s for lock;\n\r", 
  557. X          cur_folder);
  558. X    printf("** %s - %s.**\n\r\n\r", error_name(errno),
  559. X          error_description(errno));
  560. X    (void)unlink(lock_name);
  561. X    leave();
  562. X      }
  563. X
  564. X      /* try to assert lock MAX_ATTEMPTS times */
  565. X      do {
  566. X
  567. X    errno = 0;
  568. X    if(flock(flock_fd, LOCK_NB | LOCK_EX) != -1)
  569. X      break;
  570. X    else {
  571. X      if(errno != EWOULDBLOCK && errno != EAGAIN) {
  572. X
  573. X        /* Creation of lock failed NOT because it already exists!!! */
  574. X
  575. X        dprint(1, (debugfile, 
  576. X          "Error encountered attempting to flock %s\n", cur_folder));
  577. X        dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  578. X          error_description(errno)));
  579. X        MoveCursor(LINES, 0);
  580. X        printf(
  581. X     "\n\rError encountered while attempting to flock mailbox %s;\n\r", 
  582. X          cur_folder);
  583. X        printf("** %s - %s.**\n\r\n\r", error_name(errno),
  584. X          error_description(errno));
  585. X        (void)unlink(lock_name);
  586. X        leave();
  587. X      }
  588. X    }
  589. X    dprint(2, (debugfile,
  590. X      "Mailbox '%s' already locked!  Waiting...(lock)\n", cur_folder));
  591. X    error1(
  592. X      "Waiting to read mailbox while mail is being received: attempt #%d",
  593. X      flock_iteration);
  594. X    sleep(5);
  595. X      } while (flock_iteration++ < MAX_ATTEMPTS);
  596. X      clear_error();
  597. X
  598. X      if(errno != 0) {
  599. X
  600. X    /* We couldn't lock the file. We die and leave not updating
  601. X     * the mailfile mbox or any of those! */
  602. X
  603. X    if (direction == INCOMING) {
  604. X      PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations.\n\r", 
  605. X        flock_iteration);
  606. X      PutLine0(LINES, 0, 
  607. X      "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
  608. X      dprint(1, (debugfile, 
  609. X        "Warning: bailing out after %d iterations...(lock)\n",
  610. X        flock_iteration));
  611. X    } else {
  612. X      dprint(1, (debugfile, 
  613. X       "Warning: after %d iterations, timed out! (lock)\n",
  614. X       flock_iteration));
  615. X    }
  616. X#ifndef    LOCK_FLOCK_ONLY
  617. X    (void)unlink(lock_name);
  618. X#endif
  619. X    leave(error("Timed out on locking mailbox. Leaving program."));
  620. X      }
  621. X
  622. X      /* We locked the file */
  623. X      dprint(5,
  624. X    (debugfile, "Lock %s on file %s on.\n",
  625. X    (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
  626. X#endif
  627. X
  628. X      dprint(5,
  629. X    (debugfile, "Lock %s for file %s on successfully.\n",
  630. X    (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
  631. X      lock_state = ON;
  632. X      return(0);
  633. X}
  634. X
  635. Xint
  636. Xunlock()
  637. X{
  638. X    /** Remove the lock file!    This must be part of the interrupt
  639. X        processing routine to ensure that the lock file is NEVER
  640. X        left sitting in the mailhome directory!
  641. X
  642. X        If also using flock(), remove the file lock as well.
  643. X     **/
  644. X
  645. X    int retcode = 0;
  646. X
  647. X    dprint(5,
  648. X      (debugfile, "Lock %s for file %s %s off.\n",
  649. X        (*lock_name ? lock_name : "none"), cur_folder,
  650. X        (lock_state == ON ? "going" : "already")));
  651. X
  652. X    if(lock_state == ON) {
  653. X
  654. X#ifdef LOCK_BY_FLOCK
  655. X      if((retcode = flock(flock_fd, LOCK_UN)) == -1) {
  656. X        dprint(1, (debugfile,
  657. X          "Error %s (%s)\n\ttrying to unlock file %s (%s)\n", 
  658. X          error_name(errno), error_description(errno), cur_folder, "unlock"));
  659. X
  660. X        /* try to force unlock by closing file */
  661. X        if(close(flock_fd) == -1) {
  662. X          dprint(1, (debugfile,
  663. X      "Error %s (%s)\n\ttrying to force unlock file %s via close() (%s)\n", 
  664. X          error_name(errno), error_description(errno), cur_folder, "unlock"));
  665. X          error1("Couldn't unlock my own mailbox %s!", cur_folder);
  666. X          return(retcode);
  667. X        }
  668. X      }
  669. X      (void)close(flock_fd);
  670. X#endif
  671. X#ifdef    LOCK_FLOCK_ONLY    /* { LOCK_FLOCK_ONLY */
  672. X      *lock_name = '\0';        /* null lock file name */
  673. X       lock_state = OFF;        /* indicate we don't have a lock on */
  674. X#else
  675. X      if((retcode = unlink(lock_name)) == 0) {    /* remove lock file */
  676. X        *lock_name = '\0';        /* null lock file name */
  677. X        lock_state = OFF;        /* indicate we don't have a lock on */
  678. X      } else {
  679. X        dprint(1, (debugfile,
  680. X          "Error %s (%s)\n\ttrying to unlink file %s (%s)\n", 
  681. X          error_name(errno), error_description(errno), lock_name,"unlock"));
  682. X          error1("Couldn't remove my own lock file %s!", lock_name);
  683. X      }
  684. X#endif    /* } LOCK_FLOCK_ONLY */
  685. X    }
  686. X    return(retcode);
  687. X}
  688. SHAR_EOF
  689. echo "File src/leavembox.c is complete"
  690. chmod 0444 src/leavembox.c || echo "restore of src/leavembox.c fails"
  691. echo "x - extracting src/limit.c (Text)"
  692. sed 's/^X//' << 'SHAR_EOF' > src/limit.c &&
  693. X
  694. Xstatic char rcsid[] = "@(#)$Id: limit.c,v 4.1 90/04/28 22:43:21 syd Exp $";
  695. X
  696. X/*******************************************************************************
  697. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  698. X *
  699. X *             Copyright (c) 1986, 1987 Dave Taylor
  700. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  701. X *******************************************************************************
  702. X * Bug reports, patches, comments, suggestions should be sent to:
  703. X *
  704. X *    Syd Weinstein, Elm Coordinator
  705. X *    elm@DSI.COM            dsinc!elm
  706. X *
  707. X *******************************************************************************
  708. X * $Log:    limit.c,v $
  709. X * Revision 4.1  90/04/28  22:43:21  syd
  710. X * checkin of Elm 2.3 as of Release PL0
  711. X * 
  712. X *
  713. X ******************************************************************************/
  714. X
  715. X/** This stuff is inspired by MH and dmail and is used to 'select'
  716. X    a subset of the existing mail in the folder based on one of a
  717. X    number of criteria.  The basic tricks are pretty easy - we have
  718. X    as status of VISIBLE associated with each header stored in the
  719. X    (er) mind of the computer (!) and simply modify the commands to
  720. X    check that flag...the global variable `selected' is set to the
  721. X    number of messages currently selected, or ZERO if no select.
  722. X**/
  723. X
  724. X#include "headers.h"
  725. X
  726. X#define TO        1
  727. X#define FROM        2
  728. X
  729. Xchar *shift_lower();
  730. X
  731. Xint
  732. Xlimit()
  733. X{
  734. X    /** returns non-zero if we changed selection criteria = need redraw **/
  735. X    
  736. X    char criteria[STRING], first[STRING], rest[STRING], msg[STRING];
  737. X    static char prompt[] = "Enter criteria or '?' for help: ";
  738. X    int  last_selected, all;
  739. X
  740. X    last_selected = selected;
  741. X    all = 0;
  742. X
  743. X    if (selected) {
  744. X      PutLine1(LINES-2, 0, 
  745. X        "Already have selection criteria - add more? (y/n) n%c",
  746. X        BACKSPACE);
  747. X      criteria[0] = ReadCh();
  748. X      if (tolower(criteria[0]) == 'y') {
  749. X        Write_to_screen("Yes.", 0);
  750. X        PutLine0(LINES-3, COLUMNS-30, "Adding criteria...");
  751. X      } else {
  752. X        Write_to_screen("No.", 0);
  753. X        selected = 0;
  754. X        PutLine0(LINES-3, COLUMNS-30, "Change criteria...");
  755. X      }
  756. X    }
  757. X
  758. X    while(1) {
  759. X      PutLine1(LINES-2, 0, prompt);
  760. X      CleartoEOLN();
  761. X
  762. X      criteria[0] = '\0';
  763. X      optionally_enter(criteria, LINES-2, strlen(prompt), FALSE, FALSE);
  764. X      error("");
  765. X      
  766. X      if (strlen(criteria) == 0) {
  767. X        /* no change */
  768. X        selected = last_selected;
  769. X        return(FALSE);    
  770. X      }
  771. X
  772. X      split_word(criteria, first, rest);
  773. X
  774. X      if (equal(first, "?")) {
  775. X         if(last_selected)
  776. X           error(
  777. X              "Enter: {\"subject\",\"to\",\"from\"} [pattern] OR \"all\"");
  778. X         else
  779. X           error("Enter: {\"subject\",\"to\",\"from\"} [pattern]");
  780. X         continue;
  781. X      } else if (equal(first, "all")) {
  782. X        all++;
  783. X        selected = 0;
  784. X      }
  785. X      else if (equal(first, "subj") || equal(first, "subject"))
  786. X        selected = limit_selection(SUBJECT, rest, selected);
  787. X      else if (equal(first, "to"))
  788. X        selected = limit_selection(TO, rest, selected);
  789. X      else if (equal(first, "from"))
  790. X        selected = limit_selection(FROM, rest, selected);
  791. X      else {
  792. X        error1("\"%s\" not a valid criterion.", first);
  793. X        continue;
  794. X      }
  795. X      break;
  796. X    }
  797. X
  798. X    if(all && last_selected)
  799. X      strcpy(msg, "Returned to unlimited display.");
  800. X    else if(selected)
  801. X      sprintf(msg, "%d message%s selected.", selected, plural(selected));
  802. X    else
  803. X      strcpy(msg, "No messages selected.");
  804. X    set_error(msg);
  805. X
  806. X    /* we need a redraw if there had been a selection or there is now. */
  807. X    if(last_selected || selected) {
  808. X      /* if current message won't be on new display, go to first message */
  809. X      if(selected && !(headers[current-1]->status & VISIBLE))
  810. X        current = visible_to_index(1)+1;
  811. X      return(TRUE);
  812. X    } else {
  813. X      return(FALSE);
  814. X    }
  815. X}
  816. X
  817. Xint
  818. Xlimit_selection(based_on, pattern, additional_criteria)
  819. Xint based_on, additional_criteria;
  820. Xchar *pattern;
  821. X{
  822. X    /** Given the type of criteria, and the pattern, mark all
  823. X        non-matching headers as ! VISIBLE.  If additional_criteria,
  824. X        don't mark as visible something that isn't currently!
  825. X    **/
  826. X
  827. X    register int iindex, count = 0;
  828. X
  829. X    dprint(2, (debugfile, "\n\n\n**limit on %d - '%s' - (%s) **\n\n",
  830. X           based_on, pattern, additional_criteria?"add'tl":"base"));
  831. X
  832. X    if (based_on == SUBJECT) {
  833. X      for (iindex = 0; iindex < message_count; iindex++)
  834. X        if (! in_string(shift_lower(headers[iindex]->subject), pattern))
  835. X          headers[iindex]->status &= ~VISIBLE;
  836. X        else if (additional_criteria &&     
  837. X             !(headers[iindex]->status & VISIBLE))
  838. X          headers[iindex]->status &= ~VISIBLE;    /* shut down! */
  839. X        else { /* mark it as readable */
  840. X          headers[iindex]->status |= VISIBLE;
  841. X          count++;
  842. X          dprint(5, (debugfile,
  843. X             "  Message %d (%s from %s) marked as visible\n",
  844. X            iindex, headers[iindex]->subject,
  845. X            headers[iindex]->from));
  846. X        }
  847. X    }
  848. X    else if (based_on == FROM) {
  849. X      for (iindex = 0; iindex < message_count; iindex++)
  850. X        if (! in_string(shift_lower(headers[iindex]->from), pattern))
  851. X          headers[iindex]->status &= ~VISIBLE;
  852. X        else if (additional_criteria &&     
  853. X             !(headers[iindex]->status & VISIBLE))
  854. X          headers[iindex]->status &= ~VISIBLE;    /* shut down! */
  855. X        else { /* mark it as readable */
  856. X          headers[iindex]->status |= VISIBLE;
  857. X          count++;
  858. X          dprint(5, (debugfile, 
  859. X            "  Message %d (%s from %s) marked as visible\n",
  860. X            iindex, headers[iindex]->subject,
  861. X            headers[iindex]->from));
  862. X        }
  863. X    }
  864. X    else if (based_on == TO) {
  865. X      for (iindex = 0; iindex < message_count; iindex++)
  866. X        if (! in_string(shift_lower(headers[iindex]->to), pattern))
  867. X          headers[iindex]->status &= ~VISIBLE;
  868. X        else if (additional_criteria &&     
  869. X             !(headers[iindex]->status & VISIBLE))
  870. X          headers[iindex]->status &= ~VISIBLE;    /* shut down! */
  871. X        else { /* mark it as readable */
  872. X          headers[iindex]->status |= VISIBLE;
  873. X          count++;
  874. X          dprint(5, (debugfile,
  875. X            "  Message %d (%s from %s) marked as visible\n",
  876. X            iindex, headers[iindex]->subject,
  877. X            headers[iindex]->from));
  878. X        }
  879. X    }
  880. X
  881. X    dprint(4, (debugfile, "\n** returning %d selected **\n\n\n", count));
  882. X
  883. X    return(count);
  884. X}
  885. X
  886. Xint
  887. Xnext_message(iindex, skipdel)
  888. Xregister int iindex, skipdel;
  889. X{
  890. X    /** Given 'iindex', this routine will return the actual iindex into the
  891. X        array of the NEXT message, or '-1' iindex is the last.
  892. X        If skipdel, return the iindex for the NEXT undeleted message.
  893. X        If selected, return the iindex for the NEXT message marked VISIBLE.
  894. X    **/
  895. X
  896. X    register int remember_for_debug;
  897. X
  898. X    if(iindex < 0) return(-1);    /* invalid argument value! */
  899. X
  900. X    remember_for_debug = iindex;
  901. X
  902. X    for(iindex++;iindex < message_count; iindex++)
  903. X      if (((headers[iindex]->status & VISIBLE) || (!selected))
  904. X        && (!(headers[iindex]->status & DELETED) || (!skipdel))) {
  905. X          dprint(9, (debugfile, "[Next%s%s: given %d returning %d]\n", 
  906. X          (skipdel ? " undeleted" : ""),
  907. X          (selected ? " visible" : ""),
  908. X          remember_for_debug+1, iindex+1));
  909. X          return(iindex);
  910. X      }
  911. X    return(-1);
  912. X}
  913. X
  914. Xint
  915. Xprev_message(iindex, skipdel)
  916. Xregister int iindex, skipdel;
  917. X{
  918. X    /** Like next_message, but the PREVIOUS message. **/
  919. X
  920. X    register int remember_for_debug;
  921. X
  922. X    if(iindex >= message_count) return(-1);    /* invalid argument value! */
  923. X
  924. X    remember_for_debug = iindex;
  925. X    for(iindex--; iindex >= 0; iindex--)
  926. X      if (((headers[iindex]->status & VISIBLE) || (!selected))
  927. X        && (!(headers[iindex]->status & DELETED) || (!skipdel))) {
  928. X          dprint(9, (debugfile, "[Previous%s%s: given %d returning %d]\n", 
  929. X          (skipdel ? " undeleted" : ""),
  930. X          (selected ? " visible" : ""),
  931. X          remember_for_debug+1, iindex+1));
  932. X          return(iindex);
  933. X      }
  934. X    return(-1);
  935. X}
  936. X
  937. X
  938. Xint
  939. Xcompute_visible(message)
  940. Xint message;
  941. X{
  942. X    /** return the 'virtual' iindex of the specified message in the
  943. X        set of messages - that is, if we have the 25th message as
  944. X        the current one, but it's #2 based on our limit criteria,
  945. X        this routine, given 25, will return 2.
  946. X    **/
  947. X
  948. X    register int iindex, count = 0;
  949. X
  950. X    if (! selected) return(message);
  951. X
  952. X    if (message < 1) message = 1;    /* normalize */
  953. X
  954. X    for (iindex = 0; iindex < message; iindex++)
  955. X       if (headers[iindex]->status & VISIBLE) 
  956. X         count++;
  957. X
  958. X    dprint(4, (debugfile,
  959. X        "[compute-visible: displayed message %d is actually %d]\n",
  960. X        count, message));
  961. X
  962. X    return(count);
  963. X}
  964. X
  965. Xint
  966. Xvisible_to_index(message)
  967. Xint message;
  968. X{
  969. X    /** Given a 'virtual' iindex, return a real one.  This is the
  970. X        flip-side of the routine above, and returns (message_count+1)
  971. X        if it cannot map the virtual iindex requested (too big) 
  972. X    **/
  973. X
  974. X    register int iindex = 0, count = 0;
  975. X
  976. X    for (iindex = 0; iindex < message_count; iindex++) {
  977. X       if (headers[iindex]->status & VISIBLE) 
  978. X         count++;
  979. X       if (count == message) {
  980. X         dprint(4, (debugfile,
  981. X             "visible-to-index: (up) index %d is displayed as %d\n",
  982. X             message, iindex));
  983. X         return(iindex);
  984. X       }
  985. X    }
  986. X
  987. X    dprint(4, (debugfile, "index %d is NOT displayed!\n", message));
  988. X
  989. X    return(message_count+1);
  990. X}
  991. SHAR_EOF
  992. chmod 0444 src/limit.c || echo "restore of src/limit.c fails"
  993. echo "x - extracting src/mailmsg1.c (Text)"
  994. sed 's/^X//' << 'SHAR_EOF' > src/mailmsg1.c &&
  995. X
  996. Xstatic char rcsid[] = "@(#)$Id: mailmsg1.c,v 4.1 90/04/28 22:43:26 syd Exp $";
  997. X
  998. X/*******************************************************************************
  999. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1000. X *
  1001. X *             Copyright (c) 1986, 1987 Dave Taylor
  1002. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1003. X *******************************************************************************
  1004. X * Bug reports, patches, comments, suggestions should be sent to:
  1005. X *
  1006. X *    Syd Weinstein, Elm Coordinator
  1007. X *    elm@DSI.COM            dsinc!elm
  1008. X *
  1009. X *******************************************************************************
  1010. X * $Log:    mailmsg1.c,v $
  1011. X * Revision 4.1  90/04/28  22:43:26  syd
  1012. X * checkin of Elm 2.3 as of Release PL0
  1013. X * 
  1014. X *
  1015. X ******************************************************************************/
  1016. X
  1017. X/** Interface to allow mail to be sent to users.  Part of ELM  **/
  1018. X
  1019. X
  1020. X#include "headers.h"
  1021. X
  1022. X/** strings defined for the hdrconfg routines **/
  1023. X
  1024. Xchar subject[SLEN], in_reply_to[SLEN], expires[SLEN], 
  1025. X     action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], 
  1026. X     cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], 
  1027. X     expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
  1028. X     bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
  1029. X
  1030. Xchar *format_long(), *strip_commas(), *tail_of_string(), *strcpy();
  1031. Xunsigned long sleep();
  1032. X
  1033. Xint
  1034. Xsendmsg(given_to, given_cc, given_subject, edit_message, form_letter, replying)
  1035. Xchar *given_to, *given_cc, *given_subject;
  1036. Xint   edit_message, form_letter, replying;
  1037. X{
  1038. X    /** Prompt for fields and then call mail() to send the specified
  1039. X        message.  If 'edit_message' is true then don't allow the
  1040. X            message to be edited. 'form_letter' can be "YES" "NO" or "MAYBE".
  1041. X        if YES, then add the header.  If MAYBE, then add the M)ake form
  1042. X        option to the last question (see mailsg2.c) etc. etc. 
  1043. X        if (replying) then add an In-Reply-To: header...
  1044. X        Return TRUE if the main part of the screen has been changed
  1045. X        (useful for knowing whether a redraw is needed.
  1046. X    **/
  1047. X
  1048. X    int  copy_msg = FALSE, is_a_response = FALSE;
  1049. X
  1050. X    /* First: zero all current global message strings */
  1051. X
  1052. X    cc[0] = bcc[0] = reply_to[0] = expires[0] = '\0';
  1053. X    action[0] = priority[0] = user_defined_header[0] = in_reply_to[0] ='\0';
  1054. X    expanded_to[0] = expanded_cc[0] = expanded_bcc[0] = '\0';
  1055. X
  1056. X    strcpy(subject, given_subject);        /* copy given subject */
  1057. X    strcpy(to, given_to);            /* copy given to:     */
  1058. X    strcpy(cc, given_cc);            /*  and so on..       */
  1059. X
  1060. X    /******* And now the real stuff! *******/
  1061. X
  1062. X    copy_msg=copy_the_msg(&is_a_response); /* copy msg into edit buffer? */
  1063. X
  1064. X    if (get_to(to, expanded_to) == 0)   /* get the To: address and expand */
  1065. X      return(0);
  1066. X
  1067. X    /** if we're batchmailing, let's send it and GET OUTTA HERE! **/
  1068. X
  1069. X    if (batch_only) {
  1070. X      return(mail(FALSE, FALSE, form_letter));
  1071. X    }
  1072. X
  1073. X    display_to(expanded_to);    /* display the To: field on screen... */
  1074. X
  1075. X    dprint(3, (debugfile, "\nMailing to \"%s\"\n", expanded_to));
  1076. X  
  1077. X    if (get_subject(subject) == 0)        /* get the Subject: field */
  1078. X      return(0);
  1079. X
  1080. X    dprint(4, (debugfile, "Subject is %s\n", subject));
  1081. X
  1082. X    if (prompt_for_cc) {
  1083. X      if (get_copies(cc, expanded_to, expanded_cc, copy_msg) == 0)
  1084. X        return(0);
  1085. X
  1086. X      if (strlen(cc) > 0)
  1087. X        dprint(4, (debugfile, "Copies to %s\n", expanded_cc));
  1088. X    }
  1089. X
  1090. X    MoveCursor(LINES,0);    /* so you know you've hit <return> ! */
  1091. X
  1092. X    /** generate the In-Reply-To: header... **/
  1093. X
  1094. X    if (is_a_response && replying)
  1095. X      generate_reply_to(current-1);
  1096. X
  1097. X    /* and mail that puppy outta here! */
  1098. X    
  1099. X    return(mail(copy_msg, edit_message, form_letter));
  1100. X}
  1101. X
  1102. Xget_to(to_field, address)
  1103. Xchar *to_field, *address;
  1104. X{
  1105. X    /** prompt for the "To:" field, expanding into address if possible.
  1106. X        This routine returns ZERO if errored, or non-zero if okay **/
  1107. X
  1108. X    if (strlen(to_field) == 0) {
  1109. X      if (user_level < 2) {
  1110. X        PutLine0(LINES-2, 0, "Send the message to: ");
  1111. X        (void) optionally_enter(to_field, LINES-2, 21, FALSE, FALSE); 
  1112. X      }
  1113. X      else {
  1114. X        PutLine0(LINES-2, 0, "To: ");
  1115. X        (void) optionally_enter(to_field, LINES-2, 4, FALSE, FALSE); 
  1116. X      }
  1117. X      if (strlen(to_field) == 0) {
  1118. X        ClearLine(LINES-2);    
  1119. X        return(0);
  1120. X      }
  1121. X      (void) build_address(strip_commas(to_field), address); 
  1122. X    }
  1123. X    else if (mail_only) 
  1124. X      (void) build_address(strip_commas(to_field), address); 
  1125. X    else 
  1126. X      strcpy(address, to_field);
  1127. X    
  1128. X    if (strlen(address) == 0) {    /* bad address!  Removed!! */
  1129. X      ClearLine(LINES-2);
  1130. X      return(0);
  1131. X    }
  1132. X
  1133. X    return(1);        /* everything is okay... */
  1134. X}
  1135. X
  1136. Xget_subject(subject_field)
  1137. Xchar *subject_field;
  1138. X{
  1139. X    char    ch;
  1140. X
  1141. X    /** get the subject and return non-zero if all okay... **/
  1142. X    int len = 9, prompt_line;
  1143. X
  1144. X    prompt_line = mail_only ? 4 : LINES-2;
  1145. X
  1146. X    if (user_level == 0) {
  1147. X      PutLine0(prompt_line,0,"Subject of message: ");
  1148. X      len = 20;
  1149. X    }
  1150. X    else
  1151. X      PutLine0(prompt_line,0,"Subject: ");
  1152. X
  1153. X    CleartoEOLN();
  1154. X
  1155. X    if(optionally_enter(subject_field, prompt_line, len, TRUE, FALSE)==-1){
  1156. X      /** User hit the BREAK key! **/
  1157. X      MoveCursor(prompt_line,0);     
  1158. X      CleartoEOLN();
  1159. X      error("Mail not sent.");
  1160. X      return(0);
  1161. X    }
  1162. X
  1163. X    if (strlen(subject_field) == 0) {    /* zero length subject?? */
  1164. X      PutLine1(prompt_line,0,
  1165. X        "No subject - Continue with message? (y/n) n%c", BACKSPACE);
  1166. X
  1167. X      ch = ReadCh();
  1168. X      if (tolower(ch) != 'y') {    /* user says no! */
  1169. X        Write_to_screen("No.", 0);
  1170. X        ClearLine(prompt_line);
  1171. X        error("Mail not sent.");
  1172. X        return(0);
  1173. X      }
  1174. X      else {
  1175. X        Write_to_screen("Yes.", 0);
  1176. X        PutLine0(prompt_line,0,"Subject: <none>");
  1177. X        CleartoEOLN();
  1178. X      }
  1179. X    }
  1180. X
  1181. X    return(1);        /** everything is cruising along okay **/
  1182. X}
  1183. X
  1184. Xget_copies(cc_field, address, addressII, copy_message)
  1185. Xchar *cc_field, *address, *addressII;
  1186. Xint   copy_message;
  1187. X{
  1188. X    /** Get the list of people that should be cc'd, returning ZERO if
  1189. X        any problems arise.  Address and AddressII are for expanding
  1190. X        the aliases out after entry! 
  1191. X        If 'bounceback' is nonzero, add a cc to ourselves via the remote
  1192. X        site, but only if hops to machine are > bounceback threshold.
  1193. X        If copy-message, that means that we're going to have to invoke
  1194. X        a screen editor, so we'll need to delay after displaying the
  1195. X        possibly rewritten Cc: line...
  1196. X    **/
  1197. X    int prompt_line;
  1198. X
  1199. X    prompt_line = mail_only ? 5 : LINES - 1;
  1200. X    PutLine0(prompt_line,0,"Copies to: ");
  1201. X
  1202. X    fflush(stdout);
  1203. X
  1204. X    if (optionally_enter(cc_field, prompt_line, 11, FALSE, FALSE) == -1) {
  1205. X      ClearLine(prompt_line-1);
  1206. X      ClearLine(prompt_line);
  1207. X      
  1208. X      error("Mail not sent.");
  1209. X      return(0);
  1210. X    }
  1211. X    
  1212. X    /** The following test is that if the build_address routine had
  1213. X        reason to rewrite the entry given, then, if we're mailing only
  1214. X        print the new Cc line below the old one.  If we're not, then
  1215. X        assume we're in screen mode and replace the incorrect entry on
  1216. X        the line above where we are (e.g. where we originally prompted
  1217. X        for the Cc: field).
  1218. X    **/
  1219. X
  1220. X    if (build_address(strip_commas(cc_field), addressII)) {
  1221. X      PutLine1(prompt_line, 11, "%s", addressII);
  1222. X      if ((strcmp(editor, "builtin") != 0 && strcmp(editor, "none") != 0)
  1223. X          || copy_message)
  1224. X        sleep(2);
  1225. X    }
  1226. X
  1227. X    if (strlen(address) + strlen(addressII) > VERY_LONG_STRING) {
  1228. X      dprint(2, (debugfile, 
  1229. X        "String length of \"To:\" + \"Cc\" too long! (get_copies)\n"));
  1230. X      error("Too many people. Copies ignored.");
  1231. X      sleep(2);
  1232. X      cc_field[0] = '\0';
  1233. X    }
  1234. X
  1235. X    return(1);        /* everything looks okay! */
  1236. X}
  1237. X    
  1238. Xint
  1239. Xcopy_the_msg(is_a_response)
  1240. Xint *is_a_response;
  1241. X{
  1242. X    /** Returns True iff the user wants to copy the message being
  1243. X        replied to into the edit buffer before invoking the editor! 
  1244. X        Sets "is_a_response" to true if message is a response...
  1245. X    **/
  1246. X
  1247. X    int answer = FALSE;
  1248. X
  1249. X    if (forwarding)
  1250. X      answer = TRUE;
  1251. X    else if (strlen(to) > 0 && !mail_only) {  /* predefined 'to' line! */
  1252. X      if (auto_copy) 
  1253. X        answer = TRUE;
  1254. X      else 
  1255. X        answer = (want_to("Copy message? (y/n) ", 'n') == 'y');
  1256. X      *is_a_response = TRUE;
  1257. X    }
  1258. X
  1259. X    return(answer);
  1260. X}
  1261. X
  1262. Xstatic int to_line, to_col;
  1263. X
  1264. Xdisplay_to(address)
  1265. Xchar *address;
  1266. X{
  1267. X    /** Simple routine to display the "To:" line according to the
  1268. X        current configuration (etc)                   
  1269. X     **/
  1270. X    register int open_paren;
  1271. X
  1272. X    to_line = mail_only ? 3 : LINES - 3;
  1273. X    to_col = mail_only ? 0 : COLUMNS - 50;
  1274. X    if (names_only)
  1275. X      if ((open_paren = chloc(address, '(')) > 0) {
  1276. X        if (open_paren < chloc(address, ')')) {
  1277. X          output_abbreviated_to(address);
  1278. X          return;
  1279. X        } 
  1280. X      }
  1281. X    if(mail_only)
  1282. X      if(strlen(address) > 80)
  1283. X        PutLine1(to_line, to_col, "To: (%s)", 
  1284. X            tail_of_string(address, 75));
  1285. X      else
  1286. X        PutLine1(to_line, to_col, "To: %s", address);
  1287. X    else if (strlen(address) > 45) 
  1288. X      PutLine1(to_line, to_col, "To: (%s)", 
  1289. X          tail_of_string(address, 40));
  1290. X    else {
  1291. X      if (strlen(address) > 30) 
  1292. X        PutLine1(to_line, to_col, "To: %s", address);
  1293. X      else
  1294. X        PutLine1(to_line, to_col, "          To: %s", address);
  1295. X      CleartoEOLN();
  1296. X    }
  1297. X}
  1298. X
  1299. Xoutput_abbreviated_to(address)
  1300. Xchar *address;
  1301. X{
  1302. X    /** Output just the fields in parens, separated by commas if need
  1303. X        be, and up to COLUMNS-50 characters...This is only used if the
  1304. X        user is at level BEGINNER.
  1305. X    **/
  1306. X
  1307. X    char newaddress[LONG_STRING];
  1308. X    register int iindex, newindex = 0, in_paren = 0, add_len;
  1309. X
  1310. X    iindex = 0;
  1311. X
  1312. X    add_len = strlen(address);
  1313. X    while (newindex < 55 && iindex < add_len) {
  1314. X      if (address[iindex] == '(') in_paren++;
  1315. X      else if (address[iindex] == ')') { 
  1316. X        in_paren--;
  1317. X        if (iindex < add_len-4) {
  1318. X          newaddress[newindex++] = ',';
  1319. X          newaddress[newindex++] = ' ';
  1320. X        }
  1321. X      }
  1322. X      
  1323. X      /* copy if in_paren but not at the opening outer parens */
  1324. X      if (in_paren && !(address[iindex] == '(' && in_paren == 1))
  1325. X          newaddress[newindex++] = address[iindex];
  1326. X         
  1327. X      iindex++;
  1328. X    }
  1329. X
  1330. X    newaddress[newindex] = '\0';
  1331. X
  1332. X    if (mail_only)
  1333. X      if (strlen(newaddress) > 80) 
  1334. X        PutLine1(to_line, to_col, "To: (%s)", 
  1335. X           tail_of_string(newaddress, 60));
  1336. X      else
  1337. X        PutLine1(to_line, to_col, "To: %s", newaddress);
  1338. X    else if (strlen(newaddress) > 50) 
  1339. X       PutLine1(to_line, to_col, "To: (%s)", 
  1340. X           tail_of_string(newaddress, 40));
  1341. X     else {
  1342. X       if (strlen(newaddress) > 30)
  1343. X         PutLine1(to_line, to_col, "To: %s", newaddress);
  1344. X       else
  1345. X         PutLine1(to_line, to_col, "          To: %s", newaddress);
  1346. X       CleartoEOLN();
  1347. X     }
  1348. X
  1349. X    return;
  1350. X}
  1351. SHAR_EOF
  1352. chmod 0444 src/mailmsg1.c || echo "restore of src/mailmsg1.c fails"
  1353. echo "x - extracting src/mailmsg2.c (Text)"
  1354. sed 's/^X//' << 'SHAR_EOF' > src/mailmsg2.c &&
  1355. X
  1356. Xstatic char rcsid[] = "@(#)$Id: mailmsg2.c,v 4.1 90/04/28 22:43:28 syd Exp $";
  1357. X
  1358. X/*******************************************************************************
  1359. X *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  1360. X *
  1361. X *             Copyright (c) 1986, 1987 Dave Taylor
  1362. X *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  1363. X *******************************************************************************
  1364. X * Bug reports, patches, comments, suggestions should be sent to:
  1365. X *
  1366. X *    Syd Weinstein, Elm Coordinator
  1367. X *    elm@DSI.COM            dsinc!elm
  1368. X *
  1369. X *******************************************************************************
  1370. X * $Log:    mailmsg2.c,v $
  1371. X * Revision 4.1  90/04/28  22:43:28  syd
  1372. X * checkin of Elm 2.3 as of Release PL0
  1373. X * 
  1374. X *
  1375. X ******************************************************************************/
  1376. X
  1377. X/** Interface to allow mail to be sent to users.  Part of ELM  **/
  1378. X
  1379. X#include "headers.h"
  1380. X#include <errno.h>
  1381. X#include <ctype.h>
  1382. X
  1383. X#ifdef BSD 
  1384. X#undef tolower
  1385. X#undef toupper
  1386. X#endif
  1387. X
  1388. Xextern int errno;
  1389. Xextern char version_buff[];
  1390. X
  1391. Xchar *error_name(), *error_description(), *strip_parens();
  1392. Xchar *strcat(), *strcpy(), *index();
  1393. Xchar *format_long(), *strip_commas(), *tail_of_string(); 
  1394. X
  1395. Xunsigned long sleep();
  1396. X
  1397. X#ifdef SITE_HIDING 
  1398. X char *get_ctime_date();
  1399. X#endif
  1400. XFILE *write_header_info();
  1401. X
  1402. X/* these are all defined in the mailmsg1.c file! */
  1403. X
  1404. Xextern char subject[SLEN], in_reply_to[SLEN], expires[SLEN], 
  1405. X            action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], 
  1406. X        cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], 
  1407. X        expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
  1408. X        bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING];
  1409. X
  1410. X
  1411. Xint  gotten_key;
  1412. Xchar *bounce_off_remote();
  1413. X
  1414. Xmail(copy_msg, edit_message, form)
  1415. Xint  copy_msg, edit_message, form;
  1416. X{
  1417. X    /** Given the addresses and various other miscellany (specifically, 
  1418. X        'copy-msg' indicates whether a copy of the current message should 
  1419. X        be included, 'edit_message' indicates whether the message should 
  1420. X        be edited) this routine will invoke an editor for the user and 
  1421. X        then actually mail off the message. 'form' can be YES, NO, or
  1422. X        MAYBE.  YES=add "Content-Type: mailform" header, MAYBE=add the
  1423. X        M)ake form option to last question, and NO=don't worry about it!
  1424. X        Also, if 'copy_msg' = FORM, then grab the form temp file and use
  1425. X        that...
  1426. X        Return TRUE if the main part of the screen has been changed
  1427. X        (useful for knowing whether a redraw is needed.
  1428. X    **/
  1429. X
  1430. X    FILE *reply, *real_reply; /* second is post-input buffer */
  1431. X    char *whole_msg_file, *tempnam();
  1432. X    char filename[SLEN], fname[SLEN], copy_file[SLEN],
  1433. X             very_long_buffer[VERY_LONG_STRING], mailerflags[NLEN];
  1434. X    int ch, sys_status;
  1435. X    register int retransmit = FALSE; 
  1436. X    int      already_has_text = FALSE;        /* we need an ADDRESS */
  1437. X    int     signature_done = FALSE;
  1438. X    int     need_redraw = 0;
  1439. X
  1440. X    static int cancelled_msg = 0;
  1441. X
  1442. X    dprint(4, (debugfile, "\nMailing to \"%s\" (with%s editing)\n",
  1443. X          expanded_to, edit_message? "" : "out"));
  1444. X    
  1445. X    gotten_key = 0;        /* ignore previously gotten encryption key */
  1446. X
  1447. X    /** first generate the temporary filename **/
  1448. X
  1449. X    sprintf(filename,"%s%s%d", temp_dir, temp_file, getpid());
  1450. X
  1451. X    /** if possible, let's try to recall the last message? **/
  1452. X
  1453. X    if (! batch_only && copy_msg != FORM && user_level != 0)
  1454. X      retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg, 
  1455. X               &already_has_text);
  1456. X
  1457. X    /** if we're not retransmitting, create the file.. **/
  1458. X
  1459. X    if (! retransmit)
  1460. X      if ((reply = fopen(filename,"w")) == NULL) {
  1461. X        dprint(1, (debugfile, 
  1462. X               "Attempt to write to temp file %s failed with error %s (mail)\n",
  1463. X         filename, error_name(errno)));
  1464. X        if(batch_only)
  1465. X          printf("Could not create file %s (%s).\n",filename,
  1466. X         error_name(errno));
  1467. X        else
  1468. X          error2("Could not create file %s (%s).",filename,
  1469. X         error_name(errno));
  1470. X        return(need_redraw);
  1471. X      }
  1472. X
  1473. X    chown (filename, userid, groupid);
  1474. X
  1475. X    /* copy the message from standard input */
  1476. X    if (batch_only) {
  1477. X      while (fgets(very_long_buffer, VERY_LONG_STRING, stdin) != NULL) 
  1478. X        fprintf(reply, "%s", very_long_buffer);
  1479. X    }
  1480. X
  1481. X    if (copy_msg == FORM) {
  1482. X      sprintf(fname, "%s%s%d", temp_dir, temp_form_file, getpid());
  1483. X      fclose(reply);    /* we can't retransmit a form! */
  1484. X      if (access(fname,ACCESS_EXISTS) != 0) {
  1485. X        if(batch_only)
  1486. X          printf("Couldn't find forms file!\n");
  1487. X        else
  1488. X          error("Couldn't find forms file!");
  1489. X        return(need_redraw);
  1490. X      }
  1491. X      dprint(4, (debugfile, "-- renaming existing file %s to file %s --\n",
  1492. X          fname, filename));
  1493. X      rename(fname, filename);
  1494. X    }
  1495. X    else if (copy_msg && ! retransmit) {  /* if retransmit we have it! */
  1496. X      if (attribution[0]) {
  1497. X        fprintf(reply, attribution, headers[current-1]->from);
  1498. X        fputc('\n', reply);
  1499. X      }
  1500. X      else if (forwarding) {
  1501. X        fputs("Forwarded message:\n", reply);
  1502. X      }
  1503. X      if (edit_message) {
  1504. X        copy_message(prefixchars, reply, noheader, FALSE, FALSE, TRUE);
  1505. X        already_has_text = TRUE;    /* we just added it, right? */
  1506. X      }
  1507. X      else
  1508. X        copy_message("", reply, noheader, FALSE, FALSE, TRUE);
  1509. X    }
  1510. X
  1511. X        /* append signature now if we are going to use an external editor */
  1512. X    /* Don't worry about the remote/local determination too much */
  1513. X
  1514. X        if (already_has_text || 
  1515. X           (strcmp(editor,"builtin") != 0 && strcmp(editor,"none") != 0)) {
  1516. X         signature_done = TRUE;
  1517. X             if (!retransmit && copy_msg != FORM) 
  1518. X           already_has_text |= append_sig(reply);
  1519. X    }
  1520. X
  1521. X    if (! retransmit && copy_msg != FORM)
  1522. X      if (reply != NULL)
  1523. X        (void) fclose(reply);    /* on replies, it won't be open! */
  1524. X
  1525. X    /** Edit the message **/
  1526. X
  1527. X    if (edit_message)
  1528. X      create_readmsg_file();    /* for "readmsg" routine */
  1529. X
  1530. X    ch = edit_message? 'e' : ' ';    /* drop through if needed... */
  1531. X
  1532. X    /* calculate default save_file name */
  1533. X    if(auto_cc) {
  1534. X      if(save_by_name) {
  1535. X        if(force_name) {
  1536. X          strcpy(copy_file, "=");    /* signals save by 'to' logname */
  1537. X        } else {
  1538. X          strcpy(copy_file, "=?");    /* conditional save by 'to' logname */
  1539. X        }
  1540. X      } else {
  1541. X        strcpy(copy_file, "<");    /* signals save to sentmail */
  1542. X      }
  1543. X    } else *copy_file = '\0';    /* signals to not save a copy */
  1544. X
  1545. X
  1546. X    if (! batch_only) {
  1547. X      do {
  1548. X        switch (ch) {
  1549. X          case 'e': need_redraw = 1;
  1550. X            if (edit_the_message(filename, already_has_text)) {
  1551. X              cancelled_msg = TRUE;
  1552. X              return(need_redraw);
  1553. X            }
  1554. X            break;
  1555. X
  1556. X          case 'c': if (name_copy_file(copy_file))
  1557. X              need_redraw = 1;
  1558. X            break;
  1559. X
  1560. X          case 'h': edit_headers();
  1561. X            need_redraw = 1;
  1562. X            break;
  1563. X
  1564. X#ifdef ALLOW_SUBSHELL
  1565. X          case '!': if (subshell()) {
  1566. X              ClearScreen();
  1567. X              need_redraw = 1;
  1568. X            }
  1569. X            break;
  1570. X#endif
  1571. X
  1572. X          default : /* do nothing */ ;
  1573. X        }
  1574. X
  1575. X        /** ask that silly question again... **/
  1576. X  
  1577. X        if ((ch = verify_transmission(filename, &form)) == 'f') {
  1578. X          cancelled_msg = TRUE;
  1579. X          return(need_redraw);
  1580. X        }
  1581. X
  1582. X      } while (ch != 's');
  1583. X
  1584. X      if (form == YES) 
  1585. X        if (format_form(filename) < 1) {
  1586. X          cancelled_msg = TRUE;
  1587. X          return(need_redraw);
  1588. X        }
  1589. X
  1590. X      if ((reply = fopen(filename,"r")) == NULL) {
  1591. X          dprint(1, (debugfile,
  1592. X        "Attempt to open file %s for reading failed with error %s (mail)\n",
  1593. X                filename, error_name(errno)));
  1594. X          error1("Could not open reply file (%s).", error_name(errno));
  1595. X          return(need_redraw);
  1596. X      }
  1597. X    }
  1598. X    else if ((reply = fopen(filename,"r")) == NULL) {
  1599. X      dprint(1, (debugfile, 
  1600. X        "Attempt to open file %s for reading failed with error %s (mail)\n",
  1601. X             filename, error_name(errno)));
  1602. X      printf("Could not open reply file (%s).\n", error_name(errno));
  1603. X      return(need_redraw);
  1604. X    }
  1605. X
  1606. X    cancelled_msg = FALSE;    /* it ain't cancelled, is it? */
  1607. X
  1608. X    /** ask about bounceback if the user wants us to.... **/
  1609. X
  1610. X    if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM) 
  1611. SHAR_EOF
  1612. echo "End of part 17"
  1613. echo "File src/mailmsg2.c is continued in part 18"
  1614. echo "18" > s2_seq_.tmp
  1615. exit 0
  1616.