"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/quit.c" (25 Mar 2018, 18550 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "quit.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.9_vs_14.9.10.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Termination processing. TODO MBOX -> VFS; error handling: catastrophe!
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  */
    7 /*
    8  * Copyright (c) 1980, 1993
    9  *      The Regents of the University of California.  All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 #undef n_FILE
   36 #define n_FILE quit
   37 
   38 #ifndef HAVE_AMALGAMATION
   39 # include "nail.h"
   40 #endif
   41 
   42 #include <utime.h>
   43 
   44 enum quitflags {
   45    QUITFLAG_HOLD      = 1<<0,
   46    QUITFLAG_KEEP      = 1<<1,
   47    QUITFLAG_KEEPSAVE  = 1<<2,
   48    QUITFLAG_APPEND    = 1<<3
   49 };
   50 
   51 struct quitnames {
   52    enum quitflags flag;
   53    enum okeys     okey;
   54 };
   55 
   56 static struct quitnames const _quitnames[] = {
   57    {QUITFLAG_HOLD, ok_b_hold},
   58    {QUITFLAG_KEEP, ok_b_keep},
   59    {QUITFLAG_KEEPSAVE, ok_b_keepsave},
   60    {QUITFLAG_APPEND, ok_b_append}
   61 };
   62 
   63 static char _mboxname[PATH_MAX];  /* Name of mbox */
   64 
   65 /* Touch the indicated file */
   66 static void _alter(char const *name);
   67 
   68 /* Preserve all the appropriate messages back in the system mailbox, and print
   69  * a nice message indicated how many were saved.  On any error, just return -1.
   70  * Else return 0.  Incorporate the any new mail that we found */
   71 static int  writeback(FILE *res, FILE *obuf);
   72 
   73 /* Terminate an editing session by attempting to write out the user's file from
   74  * the temporary.  Save any new stuff appended to the file */
   75 static bool_t edstop(void);
   76 
   77 static void
   78 _alter(char const *name) /* TODO error handling */
   79 {
   80 #ifdef HAVE_UTIMENSAT
   81    struct timespec tsa[2];
   82 #else
   83    struct stat sb;
   84    struct utimbuf utb;
   85 #endif
   86    struct n_timespec const *tsp;
   87    NYD_ENTER;
   88 
   89    tsp = n_time_now(TRU1); /* TODO -> eventloop */
   90 
   91 #ifdef HAVE_UTIMENSAT
   92    tsa[0].tv_sec = tsp->ts_sec + 1;
   93    tsa[0].tv_nsec = tsp->ts_nsec;
   94    tsa[1].tv_nsec = UTIME_OMIT;
   95    utimensat(AT_FDCWD, name, tsa, 0);
   96 #else
   97    if (!stat(name, &sb)) {
   98       utb.actime = tsp->ts_sec;
   99       utb.modtime = sb.st_mtime;
  100       utime(name, &utb);
  101    }
  102 #endif
  103    NYD_LEAVE;
  104 }
  105 
  106 static int
  107 writeback(FILE *res, FILE *obuf) /* TODO errors */
  108 {
  109    struct message *mp;
  110    int rv = -1, p, c;
  111    NYD_ENTER;
  112 
  113    if (fseek(obuf, 0L, SEEK_SET) == -1)
  114       goto jleave;
  115 
  116    srelax_hold();
  117    for (p = 0, mp = message; PTRCMP(mp, <, message + msgCount); ++mp)
  118       if ((mp->m_flag & MPRESERVE) || !(mp->m_flag & MTOUCH)) {
  119          ++p;
  120          if (sendmp(mp, obuf, NULL, NULL, SEND_MBOX, NULL) < 0) {
  121             n_perr(mailname, 0);
  122             srelax_rele();
  123             goto jerror;
  124          }
  125          srelax();
  126       }
  127    srelax_rele();
  128 
  129    if(res != NULL){
  130       bool_t lastnl;
  131 
  132       for(lastnl = FAL0; (c = getc(res)) != EOF && putc(c, obuf) != EOF;)
  133          lastnl = (c == '\n') ? (lastnl ? TRU2 : TRU1) : FAL0;
  134       if(lastnl != TRU2)
  135          putc('\n', obuf);
  136    }
  137    ftrunc(obuf);
  138 
  139    if (ferror(obuf)) {
  140       n_perr(mailname, 0);
  141 jerror:
  142       fseek(obuf, 0L, SEEK_SET);
  143       goto jleave;
  144    }
  145    if (fseek(obuf, 0L, SEEK_SET) == -1)
  146       goto jleave;
  147 
  148    _alter(mailname);
  149    if (p == 1)
  150       fprintf(n_stdout, _("Held 1 message in %s\n"), displayname);
  151    else
  152       fprintf(n_stdout, _("Held %d messages in %s\n"), p, displayname);
  153    rv = 0;
  154 jleave:
  155    NYD_LEAVE;
  156    return rv;
  157 }
  158 
  159 static bool_t
  160 edstop(void) /* TODO oh my god */
  161 {
  162    int gotcha, c;
  163    struct message *mp;
  164    FILE *obuf = NULL, *ibuf = NULL;
  165    struct stat statb;
  166    enum n_fopen_state fs;
  167    bool_t rv;
  168    NYD_ENTER;
  169 
  170    rv = TRU1;
  171 
  172    if (mb.mb_perm == 0)
  173       goto j_leave;
  174 
  175    for (mp = message, gotcha = 0; PTRCMP(mp, <, message + msgCount); ++mp) {
  176       if (mp->m_flag & MNEW) {
  177          mp->m_flag &= ~MNEW;
  178          mp->m_flag |= MSTATUS;
  179       }
  180       if (mp->m_flag & (MODIFY | MDELETED | MSTATUS | MFLAG | MUNFLAG |
  181             MANSWER | MUNANSWER | MDRAFT | MUNDRAFT))
  182          ++gotcha;
  183    }
  184    if (!gotcha)
  185       goto jleave;
  186 
  187    rv = FAL0;
  188 
  189    /* TODO This is too simple minded?  We should regenerate an index file
  190     * TODO to be able to truly tell whether *anything* has changed!
  191     * TODO (Or better: only come here.. then!  It is an *object method!* */
  192    /* TODO Ignoring stat error is easy, huh? */
  193    if (!stat(mailname, &statb) && statb.st_size > mailsize) {
  194       if ((obuf = Ftmp(NULL, "edstop", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
  195             NULL) {
  196          n_perr(_("tmpfile"), 0);
  197          goto jleave;
  198       }
  199       if ((ibuf = n_fopen_any(mailname, "r", NULL)) == NULL) {
  200          n_perr(mailname, 0);
  201          goto jleave;
  202       }
  203 
  204       n_file_lock(fileno(ibuf), FLT_READ, 0,0, UIZ_MAX); /* TODO ign. lock err*/
  205       fseek(ibuf, (long)mailsize, SEEK_SET);
  206       while ((c = getc(ibuf)) != EOF) /* xxx bytewise??? TODO ... I/O error? */
  207          putc(c, obuf);
  208       Fclose(ibuf);
  209       ibuf = obuf;
  210       fflush_rewind(obuf);
  211       /*obuf = NULL;*/
  212    }
  213 
  214    fprintf(n_stdout, _("%s "), n_shexp_quote_cp(displayname, FAL0));
  215    fflush(n_stdout);
  216 
  217    if ((obuf = n_fopen_any(mailname, "r+", &fs)) == NULL) {
  218       int e = n_err_no;
  219       n_perr(n_shexp_quote_cp(mailname, FAL0), e);
  220       goto jleave;
  221    }
  222    n_file_lock(fileno(obuf), FLT_WRITE, 0,0, UIZ_MAX); /* TODO ign. lock err! */
  223    ftrunc(obuf);
  224 
  225    srelax_hold();
  226    c = 0;
  227    for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp) {
  228       if (mp->m_flag & MDELETED)
  229          continue;
  230       ++c;
  231       if (sendmp(mp, obuf, NULL, NULL, SEND_MBOX, NULL) < 0) {
  232          srelax_rele();
  233          n_err(_("Failed to finalize %s\n"), n_shexp_quote_cp(mailname, FAL0));
  234          goto jleave;
  235       }
  236       srelax();
  237    }
  238    srelax_rele();
  239 
  240    gotcha = (c == 0 && ibuf == NULL);
  241    if (ibuf != NULL) {
  242       bool_t lastnl;
  243 
  244       for(lastnl = FAL0; (c = getc(ibuf)) != EOF && putc(c, obuf) != EOF;)
  245          lastnl = (c == '\n') ? (lastnl ? TRU2 : TRU1) : FAL0;
  246       if(lastnl != TRU2 && (fs & n_PROTO_MASK) == n_PROTO_FILE)
  247          putc('\n', obuf);
  248    }
  249    /* May nonetheless be a broken MBOX TODO really: VFS, object KNOWS!! */
  250    else if(!gotcha && (fs & n_PROTO_MASK) == n_PROTO_FILE)
  251       n_folder_mbox_prepare_append(obuf, NULL);
  252    fflush(obuf);
  253    if (ferror(obuf)) {
  254       n_err(_("Failed to finalize %s\n"), n_shexp_quote_cp(mailname, FAL0));
  255       goto jleave;
  256    }
  257 
  258    if(gotcha){
  259       /* Non-system boxes are never removed except forced via POSIX mode */
  260 #ifdef HAVE_FTRUNCATE
  261       ftruncate(fileno(obuf), 0);
  262 #else
  263       int fd;
  264 
  265       if((fd = open(mailname, (O_WRONLY | O_CREAT | n_O_NOXY_BITS | O_TRUNC),
  266             0600)) != -1)
  267          close(fd);
  268 #endif
  269 
  270       if(ok_blook(posix) && !ok_blook(keep) && n_path_rm(mailname))
  271          fputs(_("removed\n"), n_stdout);
  272       else
  273          fputs(_("truncated\n"), n_stdout);
  274    } else
  275       fputs((ok_blook(bsdcompat) || ok_blook(bsdmsgs))
  276          ? _("complete\n") : _("updated.\n"), n_stdout);
  277    fflush(n_stdout);
  278 
  279    rv = TRU1;
  280 jleave:
  281    if (obuf != NULL)
  282       Fclose(obuf);
  283    if (ibuf != NULL)
  284       Fclose(ibuf);
  285    if(!rv){
  286       /* TODO The codebase aborted by jumping to the main loop here.
  287        * TODO The OpenBSD mailx simply ignores this error.
  288        * TODO For now we follow the latter unless we are interactive,
  289        * TODO in which case we ask the user whether the error is to be
  290        * TODO ignored or not.  More of this around here in this file! */
  291       rv = getapproval(_("Continue, possibly loosing changes"), TRU1);
  292    }
  293 j_leave:
  294    NYD_LEAVE;
  295    return rv;
  296 }
  297 
  298 FL bool_t
  299 quit(bool_t hold_sigs_on)
  300 {
  301    int p, modify, anystat, c;
  302    FILE *fbuf, *lckfp, *rbuf, *abuf;
  303    struct message *mp;
  304    struct stat minfo;
  305    bool_t rv;
  306    NYD_ENTER;
  307 
  308    if(!hold_sigs_on)
  309       hold_sigs();
  310 
  311    rv = FAL0;
  312    fbuf = lckfp = rbuf = NULL;
  313    temporary_folder_hook_unroll();
  314 
  315    /* If we are read only, we can't do anything, so just return quickly */
  316    /* TODO yet we cannot return quickly if resources have to be released!
  317     * TODO somewhen it'll be mailbox->quit() anyway, for now do it by hand
  318     *if (mb.mb_perm == 0)
  319     *   goto jleave;*/
  320    p = (mb.mb_perm == 0);
  321 
  322    switch (mb.mb_type) {
  323    case MB_FILE:
  324       break;
  325    case MB_MAILDIR:
  326       rv = maildir_quit(TRU1);
  327       goto jleave;
  328 #ifdef HAVE_POP3
  329    case MB_POP3:
  330       rv = pop3_quit(TRU1);
  331       goto jleave;
  332 #endif
  333 #ifdef HAVE_IMAP
  334    case MB_IMAP:
  335    case MB_CACHE:
  336       rv = imap_quit(TRU1);
  337       goto jleave;
  338 #endif
  339    case MB_VOID:
  340       rv = TRU1;
  341       /* FALLTHRU */
  342    default:
  343       goto jleave;
  344    }
  345    if (p) {
  346       rv = TRU1;
  347       goto jleave; /* TODO */
  348    }
  349 
  350    /* If editing (not reading system mail box), then do the work in edstop() */
  351    if (n_pstate & n_PS_EDIT) {
  352       rv = edstop();
  353       goto jleave;
  354    }
  355 
  356    /* See if there any messages to save in mbox.  If no, we
  357     * can save copying mbox to /tmp and back.
  358     *
  359     * Check also to see if any files need to be preserved.
  360     * Delete all untouched messages to keep them out of mbox.
  361     * If all the messages are to be preserved, just exit with
  362     * a message */
  363    fbuf = n_fopen_any(mailname, "r+", NULL);
  364    if (fbuf == NULL) {
  365       if (n_err_no != n_ERR_NOENT)
  366 jnewmail:
  367          fprintf(n_stdout, _("Thou hast new mail.\n"));
  368       rv = TRU1;
  369       goto jleave;
  370    }
  371 
  372    if ((lckfp = n_dotlock(mailname, fileno(fbuf), FLT_WRITE, 0,0, UIZ_MAX)
  373          ) == NULL) {
  374       n_perr(_("Unable to (dot) lock mailbox"), 0);
  375       Fclose(fbuf);
  376       fbuf = NULL;
  377       rv = getapproval(_("Continue, possibly loosing changes"), TRU1);
  378       goto jleave;
  379    }
  380 
  381    rbuf = NULL;
  382    if (!fstat(fileno(fbuf), &minfo) && minfo.st_size > mailsize) {
  383       bool_t lastnl;
  384 
  385       fprintf(n_stdout, _("New mail has arrived.\n"));
  386       rbuf = Ftmp(NULL, "quit", OF_RDWR | OF_UNLINK | OF_REGISTER);
  387       if (rbuf == NULL || fbuf == NULL)
  388          goto jnewmail;
  389       fseek(fbuf, (long)mailsize, SEEK_SET);
  390       for(lastnl = FAL0; (c = getc(fbuf)) != EOF && putc(c, rbuf) != EOF;)
  391          lastnl = (c == '\n') ? (lastnl ? TRU2 : TRU1) : FAL0;
  392       if(lastnl != TRU2)
  393          putc('\n', rbuf);
  394       fflush_rewind(rbuf);
  395    }
  396 
  397    anystat = holdbits();
  398    modify = 0;
  399    for (c = 0, p = 0, mp = message; PTRCMP(mp, <, message + msgCount); ++mp) {
  400       if (mp->m_flag & MBOX)
  401          c++;
  402       if (mp->m_flag & MPRESERVE)
  403          p++;
  404       if (mp->m_flag & MODIFY)
  405          modify++;
  406    }
  407    if (p == msgCount && !modify && !anystat) {
  408       rv = TRU1;
  409       if (p == 1)
  410          fprintf(n_stdout, _("Held 1 message in %s\n"), displayname);
  411       else if (p > 1)
  412          fprintf(n_stdout, _("Held %d messages in %s\n"), p, displayname);
  413       goto jleave;
  414    }
  415 
  416    if (c == 0) {
  417       if (p != 0) {
  418          if (writeback(rbuf, fbuf) >= 0)
  419             rv = TRU1;
  420          else
  421             rv = getapproval(_("Continue, possibly loosing changes"), TRU1);
  422          goto jleave;
  423       }
  424       goto jcream;
  425    }
  426 
  427    if (makembox() == STOP) {
  428       rv = getapproval(_("Continue, possibly loosing changes"), TRU1);
  429       goto jleave;
  430    }
  431 
  432    /* Now we are ready to copy back preserved files to the system mailbox, if
  433     * any were requested */
  434    if (p != 0) {
  435       if (writeback(rbuf, fbuf) < 0)
  436          rv = getapproval(_("Continue, possibly loosing changes"), TRU1);
  437       goto jleave;
  438    }
  439 
  440    /* Finally, remove his file.  If new mail has arrived, copy it back */
  441 jcream:
  442    if (rbuf != NULL) {
  443       abuf = fbuf;
  444       fseek(abuf, 0L, SEEK_SET);
  445       while ((c = getc(rbuf)) != EOF)
  446          putc(c, abuf);
  447       ftrunc(abuf);
  448       _alter(mailname);
  449       rv = TRU1;
  450    } else {
  451 #ifdef HAVE_FTRUNCATE
  452       ftruncate(fileno(fbuf), 0);
  453 #else
  454       int fd;
  455 
  456       if((fd = open(mailname, (O_WRONLY | O_CREAT | n_O_NOXY_BITS | O_TRUNC),
  457             0600)) != -1)
  458          close(fd);
  459 #endif
  460       if(!ok_blook(keep))
  461          n_path_rm(mailname);
  462       rv = TRU1;
  463    }
  464 jleave:
  465    if(rbuf != NULL)
  466       Fclose(rbuf);
  467    if (fbuf != NULL) {
  468       Fclose(fbuf);
  469       if (lckfp != NULL && lckfp != (FILE*)-1)
  470          Pclose(lckfp, FAL0);
  471    }
  472 
  473    if(!hold_sigs_on)
  474       rele_sigs();
  475    NYD_LEAVE;
  476    return rv;
  477 }
  478 
  479 FL int
  480 holdbits(void)
  481 {
  482    struct message *mp;
  483    int anystat, autohold, holdbit, nohold;
  484    NYD_ENTER;
  485 
  486    anystat = 0;
  487    autohold = ok_blook(hold);
  488    holdbit = autohold ? MPRESERVE : MBOX;
  489    nohold = MBOX | MSAVED | MDELETED | MPRESERVE;
  490    if (ok_blook(keepsave))
  491       nohold &= ~MSAVED;
  492    for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp) {
  493       if (mp->m_flag & MNEW) {
  494          mp->m_flag &= ~MNEW;
  495          mp->m_flag |= MSTATUS;
  496       }
  497       if (mp->m_flag & (MSTATUS | MFLAG | MUNFLAG | MANSWER | MUNANSWER |
  498             MDRAFT | MUNDRAFT))
  499          ++anystat;
  500       if (!(mp->m_flag & MTOUCH))
  501          mp->m_flag |= MPRESERVE;
  502       if (!(mp->m_flag & nohold))
  503          mp->m_flag |= holdbit;
  504    }
  505    NYD_LEAVE;
  506    return anystat;
  507 }
  508 
  509 FL enum okay
  510 makembox(void) /* TODO oh my god (also error reporting) */
  511 {
  512    struct message *mp;
  513    char *mbox, *tempQuit;
  514    int mcount, c;
  515    FILE *ibuf = NULL, *obuf, *abuf;
  516    enum n_fopen_state fs;
  517    enum okay rv = STOP;
  518    NYD_ENTER;
  519 
  520    mbox = _mboxname;
  521    mcount = 0;
  522    if (ok_blook(append)) {
  523       if ((obuf = n_fopen_any(mbox, "a+", &fs)) == NULL) {
  524          n_perr(mbox, 0);
  525          goto jleave;
  526       }
  527       if((fs & n_PROTO_MASK) == n_PROTO_FILE)
  528          n_folder_mbox_prepare_append(obuf, NULL);
  529    } else {
  530       if ((obuf = Ftmp(&tempQuit, "makembox",
  531             OF_WRONLY | OF_HOLDSIGS | OF_REGISTER)) == NULL) {
  532          n_perr(_("temporary mail quit file"), 0);
  533          goto jleave;
  534       }
  535       if ((ibuf = Fopen(tempQuit, "r")) == NULL)
  536          n_perr(tempQuit, 0);
  537       Ftmp_release(&tempQuit);
  538       if (ibuf == NULL) {
  539          Fclose(obuf);
  540          goto jleave;
  541       }
  542 
  543       if ((abuf = n_fopen_any(mbox, "r", &fs)) != NULL) {
  544          bool_t lastnl;
  545 
  546          for (lastnl = FAL0; (c = getc(abuf)) != EOF && putc(c, obuf) != EOF;)
  547             lastnl = (c == '\n') ? (lastnl ? TRU2 : TRU1) : FAL0;
  548          if(lastnl != TRU2 && (fs & n_PROTO_MASK) == n_PROTO_FILE)
  549             putc('\n', obuf);
  550 
  551          Fclose(abuf);
  552       }
  553       if (ferror(obuf)) {
  554          n_perr(_("temporary mail quit file"), 0);
  555          Fclose(ibuf);
  556          Fclose(obuf);
  557          goto jleave;
  558       }
  559       Fclose(obuf);
  560 
  561       if ((c = open(mbox, (O_WRONLY | O_CREAT | n_O_NOXY_BITS | O_TRUNC),
  562             0666)) != -1)
  563          close(c);
  564       if ((obuf = n_fopen_any(mbox, "r+", &fs)) == NULL) {
  565          n_perr(mbox, 0);
  566          Fclose(ibuf);
  567          goto jleave;
  568       }
  569    }
  570 
  571    srelax_hold();
  572    for (mp = message; PTRCMP(mp, <, message + msgCount); ++mp) {
  573       if (mp->m_flag & MBOX) {
  574          ++mcount;
  575 #ifdef HAVE_IMAP
  576          if((fs & n_PROTO_MASK) == n_PROTO_IMAP &&
  577                !n_ignore_is_any(n_IGNORE_SAVE) && imap_thisaccount(mbox)){
  578             if(imap_copy(mp, PTR2SIZE(mp - message + 1), mbox) == STOP)
  579                goto jcopyerr;
  580          }else
  581 #endif
  582          if (sendmp(mp, obuf, n_IGNORE_SAVE, NULL, SEND_MBOX, NULL) < 0) {
  583 #ifdef HAVE_IMAP
  584 jcopyerr:
  585 #endif
  586             n_perr(mbox, 0);
  587             srelax_rele();
  588             if (ibuf != NULL)
  589                Fclose(ibuf);
  590             Fclose(obuf);
  591             goto jleave;
  592          }
  593          mp->m_flag |= MBOXED;
  594          srelax();
  595       }
  596    }
  597    srelax_rele();
  598 
  599    /* Copy the user's old mbox contents back to the end of the stuff we just
  600     * saved.  If we are appending, this is unnecessary */
  601    if (!ok_blook(append)) {
  602       bool_t lastnl;
  603 
  604       rewind(ibuf);
  605       for(lastnl = FAL0; (c = getc(ibuf)) != EOF && putc(c, obuf) != EOF;)
  606          lastnl = (c == '\n') ? (lastnl ? TRU2 : TRU1) : FAL0;
  607       if(lastnl != TRU2 && (fs & n_PROTO_MASK) == n_PROTO_FILE)
  608          putc('\n', obuf);
  609       Fclose(ibuf);
  610       fflush(obuf);
  611    }
  612    ftrunc(obuf);
  613    if (ferror(obuf)) {
  614       n_perr(mbox, 0);
  615       Fclose(obuf);
  616       goto jleave;
  617    }
  618    if (Fclose(obuf) != 0) {
  619 #ifdef HAVE_IMAP
  620       if((fs & n_PROTO_MASK) != n_PROTO_IMAP)
  621 #endif
  622          n_perr(mbox, 0);
  623       goto jleave;
  624    }
  625    if (mcount == 1)
  626       fprintf(n_stdout, _("Saved 1 message in mbox\n"));
  627    else
  628       fprintf(n_stdout, _("Saved %d messages in mbox\n"), mcount);
  629    rv = OKAY;
  630 jleave:
  631    NYD_LEAVE;
  632    return rv;
  633 }
  634 
  635 FL void
  636 save_mbox_for_possible_quitstuff(void){ /* TODO try to get rid of that */
  637    char const *cp;
  638    NYD2_ENTER;
  639 
  640    if((cp = fexpand("&", FEXP_NVAR)) == NULL)
  641       cp = n_empty;
  642    n_strscpy(_mboxname, cp, sizeof _mboxname);
  643    NYD2_LEAVE;
  644 }
  645 
  646 FL int
  647 savequitflags(void)
  648 {
  649    enum quitflags qf = 0;
  650    size_t i;
  651    NYD_ENTER;
  652 
  653    for (i = 0; i < n_NELEM(_quitnames); ++i)
  654       if (n_var_oklook(_quitnames[i].okey) != NULL)
  655          qf |= _quitnames[i].flag;
  656    NYD_LEAVE;
  657    return qf;
  658 }
  659 
  660 FL void
  661 restorequitflags(int qf)
  662 {
  663    size_t i;
  664    NYD_ENTER;
  665 
  666    for (i = 0;  i < n_NELEM(_quitnames); ++i) {
  667       char *x = n_var_oklook(_quitnames[i].okey);
  668       if (qf & _quitnames[i].flag) {
  669          if (x == NULL)
  670             n_var_okset(_quitnames[i].okey, TRU1);
  671       } else if (x != NULL)
  672          n_var_okclear(_quitnames[i].okey);
  673    }
  674    NYD_LEAVE;
  675 }
  676 
  677 /* s-it-mode */