home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / src / leavembox.c < prev    next >
C/C++ Source or Header  |  1993-08-22  |  31KB  |  1,003 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: leavembox.c,v 4.1.1.6 90/12/06 13:38:55 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.6 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    leavembox.c,v $
  17.  * Revision 4.1.1.6  90/12/06  13:38:55  syd
  18.  * disable stop signal around writeback to avoid corrupted file
  19.  * From: Syd via report from Tom Davis <tdd@endure.cl.msu.edu>
  20.  *
  21.  * Revision 4.1.1.5  90/10/10  12:49:46  syd
  22.  * Fix calling sequence to copy_message calls for
  23.  * new MMDF argument
  24.  * From: Syd
  25.  *
  26.  * Revision 4.1.1.4  90/08/15  21:00:07  syd
  27.  * Change elm to not delete empty folders on a resync
  28.  * From: Syd
  29.  *
  30.  * Revision 4.1.1.3  90/06/21  22:51:52  syd
  31.  * Add time.h to includes as some OSs include needed substructure only
  32.  * from time.h
  33.  * From: Syd
  34.  *
  35.  * Revision 4.1.1.2  90/06/21  22:48:14  syd
  36.  * patch to fix up the Log headers.
  37.  * From: pdc%lunch.wpd@sgi.com (Paul Close)
  38.  *
  39.  * Revision 4.1.1.1  90/06/09  21:33:23  syd
  40.  * Some flock()s refuse to exclusively lock a fd open for read-only access.
  41.  * From: pdc%lunch.wpd@sgi.com (Paul Close)
  42.  *
  43.  * Revision 4.1  90/04/28  22:43:18  syd
  44.  * checkin of Elm 2.3 as of Release PL0
  45.  *
  46.  *
  47.  ******************************************************************************/
  48.  
  49. /** leave current folder, updating etc. as needed...
  50.  
  51. **/
  52.  
  53. #include "headers.h"
  54. #include <string.h>
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #ifdef LOCK_BY_FLOCK
  58. #include <sys/file.h>
  59. #endif
  60. #include <errno.h>
  61. #ifdef I_TIME
  62. #  include <time.h>
  63. #endif
  64. #ifdef I_SYSTIME
  65. #  include <sys/time.h>
  66. #endif
  67.  
  68.  
  69. /**********
  70.    Since a number of machines don't seem to bother to define the utimbuf
  71.    structure for some *very* obscure reason....
  72.  
  73.    Suprise, though, BSD has a different utime() entirely...*sigh*
  74. **********/
  75.  
  76. #ifndef BSD
  77. # ifdef NOUTIMBUF
  78.  
  79. struct utimbuf {
  80.     time_t    actime;        /** access time       **/
  81.     time_t    modtime;    /** modification time **/
  82.        };
  83.  
  84.  
  85. # endif /* NOUTIMBUF */
  86. #endif /* BSD */
  87.  
  88. #ifndef OS2
  89. extern int errno;
  90. #endif
  91.  
  92. char *error_name(), *error_description(), *strcpy(), *rindex();
  93. unsigned short getegid();
  94. #ifndef    _POSIX_SOURCE
  95. unsigned long sleep();
  96. #endif
  97.  
  98. int
  99. leave_mbox(resyncing, quitting, prompt)
  100. int resyncing, quitting, prompt;
  101. {
  102.     /** Close folder, deleting some messages, storing others in mbox,
  103.         and keeping others, as directed by user input and elmrc options.
  104.  
  105.         Return    1    Folder altered
  106.             0    Folder not altered
  107.             -1    New mail arrived during the process and
  108.                     closing was aborted.
  109.         If "resyncing" we are just writing out folder to reopen it. We
  110.         therefore only consider deletes and keeps, not stores to mbox.
  111.         Also we don't remove NEW status so that it can be preserved
  112.         across the resync.
  113.  
  114.         If "quitting" and "prompt" is false, then no prompting is done.
  115.         Otherwise prompting is dependent upon the variable
  116.         question_me, as set by an elmrc option.  This behavior makes
  117.         the 'q' command prompt just like 'c' and '$', while
  118.         retaining the 'Q' command for a quick exit that never
  119.         prompts.
  120.     **/
  121.  
  122.     FILE *temp;
  123.     char temp_keep_file[SLEN], buffer[SLEN];
  124.     struct stat    buf;        /* stat command  */
  125. #ifdef BSD
  126.     time_t utime_buffer[2];        /* utime command */
  127. #else
  128.     struct utimbuf utime_buffer;    /* utime command */
  129. #endif
  130. #ifdef VOIDSIG
  131.     void    (*oldstop)();
  132. #else
  133.     int    (*oldstop)();
  134. #endif
  135.     register int to_delete = 0, to_store = 0, to_keep = 0, i,
  136.              marked_deleted, marked_read, marked_unread,
  137.              last_sortby, ask_questions,  asked_storage_q,
  138.              num_chgd_status, need_to_copy;
  139.     char answer;
  140.     long bytes();
  141.  
  142.     dprint(1, (debugfile, "\n\n-- leaving folder --\n\n"));
  143.  
  144.     if (message_count == 0)
  145.       return(0);    /* nothing changed */
  146.  
  147.     ask_questions = ((quitting && !prompt) ? FALSE : question_me);
  148.  
  149.     /* YES or NO on softkeys */
  150.     if (hp_softkeys && ask_questions) {
  151.       define_softkeys(YESNO);
  152.       softkeys_on();
  153.     }
  154.  
  155.     /* Clear the exit dispositions of all messages, just in case
  156.      * they were left set by a previous call to this function
  157.      * that was interrupted by the receipt of new mail.
  158.      */
  159.     for(i = 0; i < message_count; i++)
  160.       headers[i]->exit_disposition = UNSET;
  161.  
  162.     /* Determine if deleted messages are really to be deleted */
  163.  
  164.     /* we need to know if there are none, or one, or more to delete */
  165.     for (marked_deleted=0, i=0; i<message_count && marked_deleted<2; i++)
  166.       if (ison(headers[i]->status, DELETED))
  167.         marked_deleted++;
  168.  
  169.         if(marked_deleted) {
  170.       answer = (always_del ? 'y' : 'n');    /* default answer */
  171.       if(ask_questions) {
  172.         sprintf(buffer, "Delete message%s? (y/n) ", plural(marked_deleted));
  173.         answer = want_to(buffer, answer);
  174.       }
  175.  
  176.       if(answer == 'y') {
  177.         for (i = 0; i < message_count; i++) {
  178.           if (ison(headers[i]->status, DELETED)) {
  179.         headers[i]->exit_disposition = DELETE;
  180.         to_delete++;
  181.           }
  182.         }
  183.       }
  184.     }
  185.     dprint(3, (debugfile, "Messages to delete: %d\n", to_delete));
  186.  
  187.     /* If this is a non spool file, or if we are merely resyncing,
  188.      * all messages with an unset disposition (i.e. not slated for
  189.      * deletion) are to be kept.
  190.      * Otherwise, we need to determine if read and unread messages
  191.      * are to be stored or kept.
  192.      */
  193.     if(folder_type == NON_SPOOL || resyncing) {
  194.       to_store = 0;
  195.       for (i = 0; i < message_count; i++) {
  196.         if(headers[i]->exit_disposition == UNSET) {
  197.           headers[i]->exit_disposition = KEEP;
  198.           to_keep++;
  199.         }
  200.       }
  201.     } else {
  202.  
  203.       /* Let's first see if user wants to store read messages
  204.        * that aren't slated for deletion */
  205.  
  206.       asked_storage_q = FALSE;
  207.  
  208.       /* we need to know if there are none, or one, or more marked read */
  209.       for (marked_read=0, i=0; i < message_count && marked_read < 2; i++) {
  210.         if((isoff(headers[i]->status, UNREAD))
  211.           && (headers[i]->exit_disposition == UNSET))
  212.         marked_read++;
  213.       }
  214.       if(marked_read) {
  215.         answer = (always_store ? 'y' : 'n');    /* default answer */
  216.         if(ask_questions) {
  217.           sprintf(buffer, "Move read message%s to \"received\" folder? (y/n) ",
  218.             plural(marked_read));
  219.           answer = want_to(buffer, answer);
  220.           asked_storage_q = TRUE;
  221.         }
  222.  
  223.         for (i = 0; i < message_count; i++) {
  224.           if((isoff(headers[i]->status, UNREAD))
  225.         && (headers[i]->exit_disposition == UNSET)) {
  226.  
  227.           if(answer == 'y') {
  228.             headers[i]->exit_disposition = STORE;
  229.             to_store++;
  230.           } else {
  231.             headers[i]->exit_disposition = KEEP;
  232.             to_keep++;
  233.           }
  234.           }
  235.         }
  236.       }
  237.  
  238.       /* If we asked the user if read messages should be stored,
  239.        * and if the user wanted them kept instead, then certainly the
  240.        * user would want the unread messages kept as well.
  241.        */
  242.       if(asked_storage_q && answer == 'n') {
  243.  
  244.         for (i = 0; i < message_count; i++) {
  245.           if((ison(headers[i]->status, UNREAD))
  246.         && (headers[i]->exit_disposition == UNSET)) {
  247.           headers[i]->exit_disposition = KEEP;
  248.           to_keep++;
  249.           }
  250.         }
  251.  
  252.       } else {
  253.  
  254.         /* Determine if unread messages are to be kept */
  255.  
  256.         /* we need to know if there are none, or one, or more unread */
  257.         for (marked_unread=0, i=0; i<message_count && marked_unread<2; i++)
  258.           if((ison(headers[i]->status, UNREAD))
  259.         && (headers[i]->exit_disposition == UNSET))
  260.           marked_unread++;
  261.  
  262.         if(marked_unread) {
  263.           answer = (always_keep ? 'y' : 'n');    /* default answer */
  264.           if(ask_questions) {
  265.         sprintf(buffer,
  266.           "Keep unread message%s in incoming mailbox? (y/n) ",
  267.           plural(marked_unread));
  268.         answer = want_to(buffer, answer);
  269.           }
  270.  
  271.           for (i = 0; i < message_count; i++) {
  272.         if((ison(headers[i]->status, UNREAD))
  273.           && (headers[i]->exit_disposition == UNSET)) {
  274.  
  275.             if(answer == 'n') {
  276.               headers[i]->exit_disposition = STORE;
  277.               to_store++;
  278.             } else {
  279.               headers[i]->exit_disposition = KEEP;
  280.               to_keep++;
  281.             }
  282.  
  283.         }
  284.           }
  285.         }
  286.       }
  287.     }
  288.  
  289.     dprint(3, (debugfile, "Messages to store: %d\n", to_store));
  290.     dprint(3, (debugfile, "Messages to keep: %d\n", to_keep));
  291.  
  292.     if(to_delete + to_store + to_keep != message_count) {
  293.       dprint(1, (debugfile,
  294.       "Error: %d to delete + %d to store + %d to keep != %d message cnt\n",
  295.         to_delete, to_store, to_keep, message_count));
  296.       error("Something wrong in message counts! Folder unchanged.");
  297.       emergency_exit();
  298.     }
  299.  
  300.  
  301.     /* If we are not resyncing, we are leaving the mailfile and
  302.      * the new messages are new no longer. Note that this changes
  303.      * their status.
  304.      */
  305.     if(!resyncing) {
  306.       for (i = 0; i < message_count; i++) {
  307.         if (ison(headers[i]->status, NEW)) {
  308.           clearit(headers[i]->status, NEW);
  309.           headers[i]->status_chgd = TRUE;
  310.         }
  311.       }
  312.     }
  313.  
  314.     /* If all messages are to be kept and none have changed status
  315.      * we don't need to do anything because the current folder won't
  316.      * be changed by our writing it out - unless we are resyncing, in
  317.      * which case we force the writing out of the mailfile.
  318.      */
  319.  
  320.     for (num_chgd_status = 0, i = 0; i < message_count; i++)
  321.       if(headers[i]->status_chgd == TRUE)
  322.         num_chgd_status++;
  323.  
  324.     if(!to_delete && !to_store && !num_chgd_status && !resyncing) {
  325.       dprint(3, (debugfile, "Folder keep as is!\n"));
  326.       error("Folder unchanged.");
  327.       return(0);
  328.     }
  329.  
  330.     /** we have to check to see what the sorting order was...so that
  331.         the order in which we write messages is the same as the order
  332.         of the messages originally.
  333.         We only need to do this if there are any messages to be
  334.         written out (either to keep or to store). **/
  335.  
  336.     if ((to_keep || to_store ) && sortby != MAILBOX_ORDER) {
  337.       last_sortby = sortby;
  338.       sortby = MAILBOX_ORDER;
  339.       sort_mailbox(message_count, FALSE);
  340.       sortby = last_sortby;
  341.     }
  342.  
  343.     /* Formulate message as to number of keeps, stores, and deletes.
  344.      * This is only complex so that the message is good English.
  345.      */
  346.     if (to_keep > 0) {
  347.       if (to_store > 0) {
  348.         if (to_delete > 0)
  349.           sprintf(buffer,
  350.                 "[Keeping %d message%s, storing %d, and deleting %d.]",
  351.             to_keep, plural(to_keep), to_store, to_delete);
  352.         else
  353.           sprintf(buffer, "[Keeping %d message%s and storing %d.]",
  354.             to_keep, plural(to_keep), to_store);
  355.       } else {
  356.         if (to_delete > 0)
  357.           sprintf(buffer, "[Keeping %d message%s and deleting %d.]",
  358.             to_keep, plural(to_keep), to_delete);
  359.         else
  360.           sprintf(buffer, "[Keeping %s.]",
  361.             to_keep > 1 ? "all messages" : "message");
  362.       }
  363.     } else if (to_store > 0) {
  364.       if (to_delete > 0)
  365.         sprintf(buffer, "[Storing %d message%s and deleting %d.]",
  366.           to_store, plural(to_store), to_delete);
  367.       else
  368.         sprintf(buffer, "[Storing %s.]",
  369.           to_store > 1? "all messages" : "message");
  370.  
  371.     } else {
  372.       if (to_delete > 0)
  373.         sprintf(buffer, "[Deleting all messages.]");
  374.       else
  375.         buffer[0] = '\0';
  376.     }
  377.     /* NOTE: don't use variable "buffer" till message is output later */
  378.  
  379.     /** next, let's lock the file up and make one last size check **/
  380.  
  381.     if (folder_type == SPOOL)
  382.       lock(OUTGOING);
  383.  
  384.     if (mailfile_size != bytes(cur_folder)) {
  385.       unlock();
  386.       error("New mail has just arrived. Resynchronizing...");
  387.       return(-1);
  388.     }
  389.  
  390.     /* Everything's GO - so ouput that user message and go to it. */
  391.  
  392. #ifdef SIGTSTP
  393.     oldstop = signal(SIGTSTP, SIGIGN);
  394. #endif
  395.  
  396.     dprint(2, (debugfile, "Action: %s\n", buffer));
  397.     error(buffer);
  398.  
  399.     /* Store messages slated for storage in received mail folder */
  400.     if (to_store > 0) {
  401.       if ((errno = can_open(recvd_mail, "a"))) {
  402.         error1(
  403.           "Permission to append to %s denied!  Leaving folder intact.\n",
  404.           recvd_mail);
  405.         dprint(1, (debugfile,
  406.           "Error: Permission to append to folder %s denied!! (%s)\n",
  407.           recvd_mail, "leavembox"));
  408.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  409.           error_description(errno)));
  410.         unlock();
  411. #ifdef SIGTSTP
  412.         signal(SIGTSTP, oldstop);
  413. #endif
  414.         return(0);
  415.       }
  416.       if ((temp = fopen(recvd_mail,"a")) == NULL) {
  417.         unlock();
  418.         dprint(1, (debugfile, "Error: could not append to file %s\n",
  419.           recvd_mail));
  420.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  421.           error_description(errno)));
  422.         sprintf(buffer, "Could not append to folder %s!", recvd_mail);
  423.         Centerline(LINES-1, buffer);
  424.         emergency_exit();
  425.       }
  426.       dprint(2, (debugfile, "Storing message%s ", plural(to_store)));
  427.       for (i = 0; i < message_count; i++) {
  428.         if(headers[i]->exit_disposition == STORE) {
  429.           current = i+1;
  430.           dprint(2, (debugfile, "#%d, ", current));
  431.             copy_message("", temp, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE);
  432.         }
  433.       }
  434.       fclose(temp);
  435.       dprint(2, (debugfile, "\n\n"));
  436.       chown(recvd_mail, userid, groupid);
  437.     }
  438.  
  439.     /* If there are any messages to keep, first copy them to a
  440.      * temp file, then remove original and copy whole temp file over.
  441.      */
  442.     if (to_keep > 0) {
  443.       sprintf(temp_keep_file, "%s%d%s", temp_dir, getpid(), temp_file);
  444.       if ((errno = can_open(temp_keep_file, "w"))) {
  445.         error1(
  446. "Permission to create temp file %s for writing denied! Leaving folder intact.",
  447.           temp_keep_file);
  448.         dprint(1, (debugfile,
  449.           "Error: Permission to create temp file %s denied!! (%s)\n",
  450.           temp_keep_file, "leavembox"));
  451.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  452.           error_description(errno)));
  453.         unlock();
  454. #ifdef SIGTSTP
  455.         signal(SIGTSTP, oldstop);
  456. #endif
  457.         return(0);
  458.       }
  459.       if ((temp = fopen(temp_keep_file,"w")) == NULL) {
  460.         unlock();
  461.         dprint(1, (debugfile, "Error: could not create file %s\n",
  462.           temp_keep_file));
  463.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  464.           error_description(errno)));
  465.         sprintf(buffer, "Could not create temp file %s!", temp_keep_file);
  466.         Centerline(LINES-1, buffer);
  467.         emergency_exit();
  468.       }
  469.       dprint(2, (debugfile, "Copying to temp file message%s to be kept ",
  470.         plural(to_keep)));
  471.       for (i = 0; i < message_count; i++) {
  472.         if(headers[i]->exit_disposition == KEEP) {
  473.           current = i+1;
  474.           dprint(2, (debugfile, "#%d, ", current));
  475.             copy_message("", temp, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE);
  476.         }
  477.       }
  478.       if ( fclose(temp) == EOF ) {
  479.         Write_to_screen("\n\rClose failed on temp keep file in leavembox\n\r", 0);
  480.         perror(temp_keep_file);
  481.         dprint(2, (debugfile, "\n\rfclose err on temp_keep_file - leavembox\n\r"));
  482.         rm_temps_exit();
  483.       }
  484.       dprint(2, (debugfile, "\n\n"));
  485.  
  486.     } else if (folder_type == NON_SPOOL && !keep_empty_files && !resyncing) {
  487.  
  488.       /* i.e. if no messages were to be kept and this is not a spool
  489.        * folder and we aren't keeping empty non-spool folders,
  490.        * simply remove the old original folder and that's it!
  491.        */
  492.           fclose(mailfile);
  493.       (void)unlink(cur_folder);
  494. #ifdef SIGTSTP
  495.       signal(SIGTSTP, oldstop);
  496. #endif
  497.       return(1);
  498.     }
  499.  
  500.     /* Otherwise we have some work left to do! */
  501.  
  502.     /* Get original permissions and access time of the original
  503.      * mail folder before we remove it.
  504.      */
  505.     if(save_file_stats(cur_folder) != 0) {
  506.       error1("Problems saving permissions of folder %s!", cur_folder);
  507.       sleep(2);
  508.     }
  509.  
  510.         if (stat(cur_folder, &buf) != 0) {
  511.       dprint(1, (debugfile, "Error: errno %s attempting to stat file %s\n",
  512.              error_name(errno), cur_folder));
  513.           error3("Error %s (%s) on stat(%s).", error_name(errno),
  514.         error_description(errno), cur_folder);
  515.     }
  516.  
  517.     /* Close and remove the original folder.
  518.      * However, if we are going to copy a temp file of kept messages
  519.      * to it, and this is a locked (spool) mailbox, we need to keep
  520.      * it locked during this process. Unfortunately,
  521.      * if we did our LOCK_BY_FLOCK, unlinking the original will kill the
  522.      * lock, so we have to resort to copying the temp file to the original
  523.      * file while keeping the original open.
  524.      * Also, if the file has a link count > 1, then it has links, so to
  525.      * prevent destroying the links, we do a copy back, even though its
  526.      * slower.
  527.      */
  528.  
  529.     fclose(mailfile);
  530.  
  531.     if(to_keep) {
  532. #ifdef LOCK_BY_FLOCK
  533.       need_to_copy = (folder_type == SPOOL ? TRUE : FALSE);
  534. #else
  535.       need_to_copy = FALSE;
  536. #endif
  537.       if (buf.st_nlink > 1)
  538.         need_to_copy = TRUE;
  539.  
  540.       if(!need_to_copy) {
  541.             fclose(mailfile);
  542.         unlink(cur_folder);
  543.         if (link(temp_keep_file, cur_folder) != 0) {
  544.           if(errno == EXDEV || errno == EEXIST) {
  545.         /* oops - can't link across file systems - use copy instead */
  546.         need_to_copy = TRUE;
  547.           } else {
  548.         dprint(1, (debugfile, "link(%s, %s) failed (leavembox)\n",
  549.                temp_keep_file, cur_folder));
  550.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  551.               error_description(errno)));
  552.         error2("Link failed! %s - %s.", error_name(errno),
  553.           error_description(errno));
  554.         unlock();
  555.         emergency_exit();
  556.           }
  557.         }
  558.       }
  559.  
  560.       if(need_to_copy) {
  561.  
  562.         if (copy(temp_keep_file, cur_folder) != 0) {
  563.  
  564.           /* copy to cur_folder failed - try to copy to special file */
  565.           dprint(1, (debugfile, "leavembox: copy(%s, %s) failed;",
  566.               temp_keep_file, cur_folder));
  567.           dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  568.            error_description(errno)));
  569.           error("Couldn't modify folder!");
  570.           sleep(1);
  571.           sprintf(cur_folder,"%s/%s", home, unedited_mail);
  572.           if (copy(temp_keep_file, cur_folder) != 0) {
  573.  
  574.         /* couldn't copy to special file either */
  575.         dprint(1, (debugfile,
  576.             "leavembox: couldn't copy to %s either!!  Help;",
  577.             cur_folder));
  578.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  579.             error_description(errno)));
  580.         error("Can't copy mailbox, system trouble!!!");
  581.         unlock();
  582.         emergency_exit();
  583.           } else {
  584.         dprint(1, (debugfile,
  585.             "\nWoah! Confused - Saved mail in %s (leavembox)\n",
  586.             cur_folder));
  587.         error1("Saved mail in %s.", cur_folder);
  588.         sleep(1);
  589.           }
  590.         }
  591.       }
  592.  
  593.       /* link or copy complete - remove temp keep file */
  594.       unlink(temp_keep_file);
  595.  
  596.     } else if(folder_type == SPOOL || keep_empty_files || resyncing) {
  597.  
  598.       /* if this is an empty spool file, or if this is an empty non spool
  599.        * file and we keep empty non spool files (we always keep empty
  600.        * spool files), create an empty file */
  601.  
  602.       if(folder_type == NON_SPOOL)
  603.         error1("Keeping empty folder '%s'.", cur_folder);
  604.       temp = fopen(cur_folder, "w");
  605.       fclose(temp);
  606.     }
  607.  
  608.     /* restore permissions and access times of folder */
  609.  
  610.     if(restore_file_stats(cur_folder) != 1) {
  611.       error1("Problems restoring permissions of folder %s!", cur_folder);
  612.       sleep(2);
  613.     }
  614.  
  615. #ifdef BSD
  616.     utime_buffer[0]     = buf.st_atime;
  617.     utime_buffer[1]     = buf.st_mtime;
  618. #else
  619.     utime_buffer.actime = buf.st_atime;
  620.     utime_buffer.modtime= buf.st_mtime;
  621. #endif
  622.  
  623. #ifdef BSD
  624.     if (utime(cur_folder, utime_buffer) != 0) {
  625. #else
  626.     if (utime(cur_folder, &utime_buffer) != 0) {
  627. #endif
  628.       dprint(1, (debugfile,
  629.          "Error: encountered error doing utime (leavmbox)\n"));
  630.       dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  631.            error_description(errno)));
  632.       error2("Error %s trying to change file %s access time.",
  633.            error_name(errno), cur_folder);
  634.     }
  635.  
  636.  
  637.     mailfile_size = bytes(cur_folder);
  638.     unlock();    /* remove the lock on the file ASAP! */
  639.  
  640. #ifdef SIGTSTP
  641.     signal(SIGTSTP, oldstop);
  642. #endif
  643.     return(1);
  644. }
  645.  
  646. static int  lock_state = OFF;
  647.  
  648. static char lock_name[SLEN];
  649.  
  650. char *
  651. mk_lockname(file_to_lock)
  652. char *file_to_lock;
  653. {
  654.     /** Create the proper name of the lock file for file_to_lock,
  655.         which is presumed to be a spool file full path (see
  656.         get_folder_type()), and put it in the static area lock_name.
  657.         Return lock_name for informational purposes.
  658.      **/
  659.     char *ptr;
  660.  
  661. #ifdef XENIX
  662.     /* lock is /tmp/[basename of file_to_lock].mlk */
  663.     sprintf(lock_name, "/tmp/%.10s.mlk", rindex(file_to_lock, '/')+1);
  664. #else
  665.     /* lock is [file_to_lock].lock */
  666.     strcpy(lock_name, file_to_lock);
  667. #ifdef OS2
  668.     if ( (ptr = strrchr(lock_name, '.')) != NULL
  669.          && strcmp(ptr, mailext) == 0 )
  670.       *ptr = 0;
  671. #endif
  672.     strcat(lock_name, ".lck");
  673. #endif
  674.     return(lock_name);
  675. }
  676.  
  677.  
  678. static int flock_fd,    /* file descriptor for flocking mailbox itself */
  679.        create_fd;    /* file descriptor for creating lock file */
  680.  
  681. lock(direction)
  682. int direction;
  683. {
  684.       /** Create lock file to ensure that we don't get any mail
  685.       while altering the folder contents!
  686.       If it already exists sit and spin until
  687.          either the lock file is removed...indicating new mail
  688.       or
  689.          we have iterated MAX_ATTEMPTS times, in which case we
  690.          either fail or remove it and make our own (determined
  691.          by if REMOVE_AT_LAST is defined in header file
  692.  
  693.       If direction == INCOMING then DON'T remove the lock file
  694.       on the way out!  (It'd mess up whatever created it!).
  695.  
  696.       But if that succeeds and if we are also locking by flock(),
  697.       follow a similar algorithm. Now if we can't lock by flock(),
  698.       we DO need to remove the lock file, since if we got this far,
  699.       we DID create it, not another process.
  700.       **/
  701.  
  702.       register int create_iteration = 0,
  703.            flock_iteration = 0;
  704.       char pid_buffer[SHORT];
  705.  
  706. #ifndef    LOCK_FLOCK_ONLY        /* { LOCK_FLOCK_ONLY    */
  707.       /* formulate lock file name */
  708.       mk_lockname(cur_folder);
  709.  
  710. #ifdef PIDCHECK
  711.       /** first, try to read the lock file, and if possible, check the pid.
  712.       If we can validate that the pid is no longer active, then remove
  713.       the lock file.
  714.        **/
  715.       if((create_fd=open(lock_name,O_RDONLY)) != -1) {
  716.     if (read(create_fd, pid_buffer, SHORT) > 0) {
  717.       create_iteration = atoi(pid_buffer);
  718.       if (create_iteration) {
  719.         if (kill(create_iteration, 0)) {
  720.           close(create_fd);
  721.           if (unlink(lock_name) != 0) {
  722.         dprint(1, (debugfile,
  723.           "Error %s (%s)\n\ttrying to unlink file %s (%s)\n",
  724.           error_name(errno), error_description(errno), lock_name, "lock"));
  725.         PutLine1(LINES, 0,
  726.           "\n\rCouldn't remove the current lock file %s\n\r", lock_name);
  727.         PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  728.           error_description(errno));
  729.         if (direction == INCOMING)
  730.           leave();
  731.         else
  732.           emergency_exit();
  733.           }
  734.         }
  735.       }
  736.     }
  737.     create_iteration = 0;
  738.       }
  739. #endif
  740.  
  741.       /* try to assert create lock file MAX_ATTEMPTS times */
  742.       do {
  743.  
  744.     errno = 0;
  745.     if((create_fd=open(lock_name,O_WRONLY | O_CREAT | O_EXCL,0666)) != -1)
  746.       break;
  747.     else {
  748.       if(errno != EEXIST) {
  749.         /* Creation of lock failed NOT because it already exists!!! */
  750.  
  751.         if (direction == OUTGOING) {
  752.           dprint(1, (debugfile,
  753.         "Error encountered attempting to create lock %s\n", lock_name));
  754.           dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  755.             error_description(errno)));
  756.           MoveCursor(LINES, 0);
  757.           printf(
  758.        "\n\rError encountered while attempting to create lock file %s;\n\r",
  759.         lock_name);
  760.           printf("** %s - %s.**\n\r\n\r",
  761.         error_name(errno), error_description(errno));
  762.         } else {    /* incoming - permission denied in the middle?  Odd. */
  763.           dprint(1, (debugfile,
  764.            "Can't create lock file: creat(%s) raises error %s (lock)\n",
  765.         lock_name, error_name(errno)));
  766.           error1(
  767.            "Can't create lock file! Need write permission in \"%s\".\n\r",
  768.         mailhome);
  769.         }
  770.         leave();
  771.       }
  772.     }
  773.     dprint(2, (debugfile,"File '%s' already exists!  Waiting...(lock)\n",
  774.       lock_name));
  775.     error1(
  776.       "Waiting to read mailbox while mail is being received: attempt #%d",
  777.       create_iteration);
  778.     sleep(5);
  779.       } while (create_iteration++ < MAX_ATTEMPTS);
  780.       clear_error();
  781.  
  782.       if(errno != 0 && errno != ENOENT) {
  783.  
  784.     /* we weren't able to create the lock file */
  785.  
  786. #ifdef REMOVE_AT_LAST
  787.  
  788.     /** time to waste the lock file!  Must be there in error! **/
  789.     dprint(2, (debugfile,
  790.        "Warning: I'm giving up waiting - removing lock file(lock)\n"));
  791.     if (direction == INCOMING)
  792.       PutLine0(LINES, 0,"\nTimed out - removing current lock file...");
  793.     else
  794.       error("Throwing away the current lock file!");
  795.  
  796.     if (unlink(lock_name) != 0) {
  797.       dprint(1, (debugfile,
  798.         "Error %s (%s)\n\ttrying to unlink file %s (%s)\n",
  799.         error_name(errno), error_description(errno), lock_name, "lock"));
  800.       PutLine1(LINES, 0,
  801.         "\n\rCouldn't remove the current lock file %s\n\r", lock_name);
  802.       PutLine2(LINES, 0, "** %s - %s **\n\r", error_name(errno),
  803.         error_description(errno));
  804.       if (direction == INCOMING)
  805.         leave();
  806.       else
  807.         emergency_exit();
  808.     }
  809.  
  810.     /* we've removed the bad lock, let's try to assert lock once more */
  811.     if((create_fd=open(lock_name,O_WRONLY | O_CREAT | O_EXCL,0666)) == -1){
  812.  
  813.       /* still can't lock it - just give up */
  814.       dprint(1, (debugfile,
  815.         "Error encountered attempting to create lock %s\n", lock_name));
  816.       dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  817.         error_description(errno)));
  818.       MoveCursor(LINES, 0);
  819.       printf(
  820.       "\n\rError encountered while attempting to create lock file %s;\n\r",
  821.         lock_name);
  822.       printf("** %s - %s.**\n\r\n\r", error_name(errno),
  823.         error_description(errno));
  824.       leave();
  825.     }
  826. #else
  827.     /* Okay...we die and leave, not updating the mailfile mbox or
  828.        any of those! */
  829.  
  830.     if (direction == INCOMING) {
  831.       PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations.\n\r",
  832.         create_iteration);
  833.       PutLine0(LINES, 0,
  834.       "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
  835.       dprint(1, (debugfile,
  836.         "Warning: bailing out after %d iterations...(lock)\n",
  837.         create_iteration));
  838.       leave_locked(0);
  839.     } else {
  840.       dprint(1, (debugfile,
  841.        "Warning: after %d iterations, timed out! (lock)\n",
  842.        create_iteration));
  843.       leave(error("Timed out on locking mailbox.  Leaving program."));
  844.     }
  845. #endif
  846.       }
  847.  
  848.       /* If we're here we successfully created the lock file */
  849.       dprint(5,
  850.     (debugfile, "Lock %s %s for file %s on.\n", lock_name,
  851.     (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
  852.  
  853.       /* Place the pid of Elm into the lock file for SVR3.2 and its ilk */
  854.       sprintf(pid_buffer, "%d", getpid());
  855.       write(create_fd, pid_buffer, strlen(pid_buffer));
  856.  
  857.       (void)close(create_fd);
  858. #endif                /* } LOCK_FLOCK_ONLY */
  859.  
  860. #ifdef LOCK_BY_FLOCK
  861.       /* Now we also need to lock the file with flock(2) */
  862.  
  863.       /* Open mail file separately for locking */
  864.       if((flock_fd = open(cur_folder, O_RDWR)) < 0) {
  865.     dprint(1, (debugfile,
  866.         "Error encountered attempting to reopen %s for lock\n", cur_folder));
  867.     dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  868.         error_description(errno)));
  869.     MoveCursor(LINES, 0);
  870.     printf(
  871.  "\n\rError encountered while attempting to reopen mailbox %s for lock;\n\r",
  872.           cur_folder);
  873.     printf("** %s - %s.**\n\r\n\r", error_name(errno),
  874.           error_description(errno));
  875.     (void)unlink(lock_name);
  876.     leave();
  877.       }
  878.  
  879.       /* try to assert lock MAX_ATTEMPTS times */
  880.       do {
  881.  
  882.     errno = 0;
  883.     if(flock(flock_fd, LOCK_NB | LOCK_EX) != -1)
  884.       break;
  885.     else {
  886.       if(errno != EWOULDBLOCK && errno != EAGAIN) {
  887.  
  888.         /* Creation of lock failed NOT because it already exists!!! */
  889.  
  890.         dprint(1, (debugfile,
  891.           "Error encountered attempting to flock %s\n", cur_folder));
  892.         dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  893.           error_description(errno)));
  894.         MoveCursor(LINES, 0);
  895.         printf(
  896.      "\n\rError encountered while attempting to flock mailbox %s;\n\r",
  897.           cur_folder);
  898.         printf("** %s - %s.**\n\r\n\r", error_name(errno),
  899.           error_description(errno));
  900.         (void)unlink(lock_name);
  901.         leave();
  902.       }
  903.     }
  904.     dprint(2, (debugfile,
  905.       "Mailbox '%s' already locked!  Waiting...(lock)\n", cur_folder));
  906.     error1(
  907.       "Waiting to read mailbox while mail is being received: attempt #%d",
  908.       flock_iteration);
  909.     sleep(5);
  910.       } while (flock_iteration++ < MAX_ATTEMPTS);
  911.       clear_error();
  912.  
  913.       if(errno != 0) {
  914.  
  915.     /* We couldn't lock the file. We die and leave not updating
  916.      * the mailfile mbox or any of those! */
  917.  
  918.     if (direction == INCOMING) {
  919.       PutLine1(LINES, 0, "\n\r\n\rGiving up after %d iterations.\n\r",
  920.         flock_iteration);
  921.       PutLine0(LINES, 0,
  922.       "\n\rPlease try to read your mail again in a few minutes.\n\r\n\r");
  923.       dprint(1, (debugfile,
  924.         "Warning: bailing out after %d iterations...(lock)\n",
  925.         flock_iteration));
  926.     } else {
  927.       dprint(1, (debugfile,
  928.        "Warning: after %d iterations, timed out! (lock)\n",
  929.        flock_iteration));
  930.     }
  931. #ifndef    LOCK_FLOCK_ONLY
  932.     (void)unlink(lock_name);
  933. #endif
  934.     leave(error("Timed out on locking mailbox. Leaving program."));
  935.       }
  936.  
  937.       /* We locked the file */
  938.       dprint(5,
  939.     (debugfile, "Lock %s on file %s on.\n",
  940.     (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
  941. #endif
  942.  
  943.       dprint(5,
  944.     (debugfile, "Lock %s for file %s on successfully.\n",
  945.     (direction == INCOMING ? "incoming" : "outgoing"), cur_folder));
  946.       lock_state = ON;
  947.       return(0);
  948. }
  949.  
  950. int
  951. unlock()
  952. {
  953.     /** Remove the lock file!    This must be part of the interrupt
  954.         processing routine to ensure that the lock file is NEVER
  955.         left sitting in the mailhome directory!
  956.  
  957.         If also using flock(), remove the file lock as well.
  958.      **/
  959.  
  960.     int retcode = 0;
  961.  
  962.     dprint(5,
  963.       (debugfile, "Lock %s for file %s %s off.\n",
  964.         (*lock_name ? lock_name : "none"), cur_folder,
  965.         (lock_state == ON ? "going" : "already")));
  966.  
  967.     if(lock_state == ON) {
  968.  
  969. #ifdef LOCK_BY_FLOCK
  970.       if((retcode = flock(flock_fd, LOCK_UN)) == -1) {
  971.         dprint(1, (debugfile,
  972.           "Error %s (%s)\n\ttrying to unlock file %s (%s)\n",
  973.           error_name(errno), error_description(errno), cur_folder, "unlock"));
  974.  
  975.         /* try to force unlock by closing file */
  976.         if(close(flock_fd) == -1) {
  977.           dprint(1, (debugfile,
  978.       "Error %s (%s)\n\ttrying to force unlock file %s via close() (%s)\n",
  979.           error_name(errno), error_description(errno), cur_folder, "unlock"));
  980.           error1("Couldn't unlock my own mailbox %s!", cur_folder);
  981.           return(retcode);
  982.         }
  983.       }
  984.       (void)close(flock_fd);
  985. #endif
  986. #ifdef    LOCK_FLOCK_ONLY    /* { LOCK_FLOCK_ONLY */
  987.       *lock_name = '\0';        /* null lock file name */
  988.        lock_state = OFF;        /* indicate we don't have a lock on */
  989. #else
  990.       if((retcode = unlink(lock_name)) == 0) {    /* remove lock file */
  991.         *lock_name = '\0';        /* null lock file name */
  992.         lock_state = OFF;        /* indicate we don't have a lock on */
  993.       } else {
  994.         dprint(1, (debugfile,
  995.           "Error %s (%s)\n\ttrying to unlink file %s (%s)\n",
  996.           error_name(errno), error_description(errno), lock_name,"unlock"));
  997.           error1("Couldn't remove my own lock file %s!", lock_name);
  998.       }
  999. #endif    /* } LOCK_FLOCK_ONLY */
  1000.     }
  1001.     return(retcode);
  1002. }
  1003.