"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/quit.c" (8 Aug 2018, 18680 Bytes) of package /linux/misc/s-nail-14.9.11.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.10_vs_14.9.11.

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