"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.7/cmd-message.c" (16 Feb 2018, 23254 Bytes) of package /linux/misc/s-nail-14.9.7.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 "cmd-message.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.6_vs_14.9.7.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Iterating over, and over such housekeeping message user commands.
    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 cmd_message
   37 
   38 #ifndef HAVE_AMALGAMATION
   39 # include "nail.h"
   40 #endif
   41 
   42 /* Prepare and print "[Message: xy]:" intro */
   43 static bool_t a_cmsg_show_overview(FILE *obuf, struct message *mp, int msg_no);
   44 
   45 /* Show the requested messages */
   46 static int     _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
   47                   bool_t donotdecode, char *cmd, ui64_t *tstats);
   48 
   49 /* Pipe the requested messages */
   50 static int     _pipe1(char *str, int doign);
   51 
   52 /* `top' / `Top' */
   53 static int a_cmsg_top(void *vp, struct n_ignore const *itp);
   54 
   55 /* Delete the indicated messages.  Set dot to some nice place afterwards */
   56 static int     delm(int *msgvec);
   57 
   58 static bool_t
   59 a_cmsg_show_overview(FILE *obuf, struct message *mp, int msg_no){
   60    bool_t rv;
   61    char const *cpre, *csuf;
   62    NYD2_ENTER;
   63 
   64    cpre = csuf = n_empty;
   65 #ifdef HAVE_COLOUR
   66    if(n_COLOUR_IS_ACTIVE()){
   67       struct n_colour_pen *cpen;
   68 
   69       if((cpen = n_colour_pen_create(n_COLOUR_ID_VIEW_MSGINFO, NULL)) != NULL){
   70          struct str const *sp;
   71 
   72          if((sp = n_colour_pen_to_str(cpen)) != NULL)
   73             cpre = sp->s;
   74          if((sp = n_colour_reset_to_str()) != NULL)
   75             csuf = sp->s;
   76       }
   77    }
   78 #endif
   79    /* XXX Message info uses wire format for line count */
   80    rv = (fprintf(obuf, _("%s[-- Message %2d -- %lu lines, %lu bytes --]:%s\n"),
   81          cpre, msg_no, (ul_i)mp->m_lines, (ul_i)mp->m_size, csuf) > 0);
   82    NYD2_LEAVE;
   83    return rv;
   84 }
   85 
   86 static int
   87 _type1(int *msgvec, bool_t doign, bool_t dopage, bool_t dopipe,
   88    bool_t donotdecode, char *cmd, ui64_t *tstats)
   89 {
   90    ui64_t mstats[1];
   91    int *ip;
   92    struct message *mp;
   93    char const *cp;
   94    enum sendaction action;
   95    bool_t volatile formfeed;
   96    FILE * volatile obuf;
   97    int volatile rv;
   98    NYD_ENTER;
   99 
  100    rv = 1;
  101    obuf = n_stdout;
  102    formfeed = (dopipe && ok_blook(page));
  103    action = ((dopipe && ok_blook(piperaw))
  104          ? SEND_MBOX : donotdecode
  105          ? SEND_SHOW : doign
  106          ? SEND_TODISP : SEND_TODISP_ALL);
  107 
  108    if (dopipe) {
  109       if ((obuf = Popen(cmd, "w", ok_vlook(SHELL), NULL, 1)) == NULL) {
  110          n_perr(cmd, 0);
  111          obuf = n_stdout;
  112       }
  113    } else if ((n_psonce & n_PSO_TTYOUT) && (dopage ||
  114          ((n_psonce & n_PSO_INTERACTIVE) && (cp = ok_vlook(crt)) != NULL))) {
  115       uiz_t nlines, lib;
  116 
  117       nlines = 0;
  118 
  119       if (!dopage) {
  120          for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
  121             mp = message + *ip - 1;
  122             if (!(mp->m_content_info & CI_HAVE_BODY))
  123                if (get_body(mp) != OKAY)
  124                   goto jleave;
  125             nlines += mp->m_lines + 1; /* TODO BUT wire format, not display! */
  126          }
  127       }
  128 
  129       /* >= not <: we return to the prompt */
  130       if(dopage || nlines >= (*cp != '\0'
  131                ? (n_idec_uiz_cp(&lib, cp, 0, NULL), lib)
  132                : (uiz_t)n_realscreenheight)){
  133          if((obuf = n_pager_open()) == NULL)
  134             obuf = n_stdout;
  135       }
  136       n_COLOUR(
  137          if(action == SEND_TODISP || action == SEND_TODISP_ALL)
  138             n_colour_env_create(n_COLOUR_CTX_VIEW, obuf, obuf != n_stdout);
  139       )
  140    }
  141    n_COLOUR(
  142       else if(action == SEND_TODISP || action == SEND_TODISP_ALL)
  143          n_colour_env_create(n_COLOUR_CTX_VIEW, n_stdout, FAL0);
  144    )
  145 
  146    rv = 0;
  147    srelax_hold();
  148    for (ip = msgvec; *ip && PTRCMP(ip - msgvec, <, msgCount); ++ip) {
  149       mp = message + *ip - 1;
  150       touch(mp);
  151       setdot(mp);
  152       n_pstate |= n_PS_DID_PRINT_DOT;
  153       uncollapse1(mp, 1);
  154       if(!dopipe && ip != msgvec && fprintf(obuf, "\n") < 0){
  155          rv = 1;
  156          break;
  157       }
  158       if(action != SEND_MBOX && !a_cmsg_show_overview(obuf, mp, *ip)){
  159          rv = 1;
  160          break;
  161       }
  162       if(sendmp(mp, obuf, (doign ? n_IGNORE_TYPE : NULL), NULL, action, mstats
  163             ) < 0){
  164          rv = 1;
  165          break;
  166       }
  167       srelax();
  168       if(formfeed){ /* TODO a nicer way to separate piped messages! */
  169          if(putc('\f', obuf) == EOF){
  170             rv = 1;
  171             break;
  172          }
  173       }
  174       if (tstats != NULL)
  175          tstats[0] += mstats[0];
  176    }
  177    srelax_rele();
  178    n_COLOUR(
  179       if(!dopipe && (action == SEND_TODISP || action == SEND_TODISP_ALL))
  180          n_colour_env_gut();
  181    )
  182 jleave:
  183    if (obuf != n_stdout)
  184       n_pager_close(obuf);
  185    NYD_LEAVE;
  186    return rv;
  187 }
  188 
  189 static int
  190 _pipe1(char *str, int doign)
  191 {
  192    ui64_t stats[1];
  193    char const *cmd, *cmdq;
  194    int *msgvec, rv = 1;
  195    bool_t needs_list;
  196    NYD_ENTER;
  197 
  198    if ((cmd = laststring(str, &needs_list, TRU1)) == NULL) {
  199       cmd = ok_vlook(cmd);
  200       if (cmd == NULL || *cmd == '\0') {
  201          n_err(_("Variable *cmd* not set\n"));
  202          goto jleave;
  203       }
  204    }
  205 
  206    msgvec = salloc((msgCount + 2) * sizeof *msgvec);
  207 
  208    if (!needs_list) {
  209       *msgvec = first(0, MMNORM);
  210       if (*msgvec == 0) {
  211          if (n_pstate & (n_PS_ROBOT | n_PS_HOOK_MASK)) {
  212             rv = 0;
  213             goto jleave;
  214          }
  215          fputs(_("No messages to pipe.\n"), n_stdout);
  216          goto jleave;
  217       }
  218       msgvec[1] = 0;
  219    } else if (getmsglist(str, msgvec, 0) < 0)
  220       goto jleave;
  221    if (*msgvec == 0) {
  222       if (n_pstate & (n_PS_ROBOT | n_PS_HOOK_MASK)) {
  223          rv = 0;
  224          goto jleave;
  225       }
  226       fprintf(n_stdout, "No applicable messages.\n");
  227       goto jleave;
  228    }
  229 
  230    cmdq = n_shexp_quote_cp(cmd, FAL0);
  231    fprintf(n_stdout, _("Pipe to: %s\n"), cmdq);
  232    stats[0] = 0;
  233    if ((rv = _type1(msgvec, doign, FAL0, TRU1, FAL0, n_UNCONST(cmd), stats)
  234          ) == 0)
  235       fprintf(n_stdout, "%s %" PRIu64 " bytes\n", cmdq, stats[0]);
  236 jleave:
  237    NYD_LEAVE;
  238    return rv;
  239 }
  240 
  241 static int
  242 a_cmsg_top(void *vp, struct n_ignore const *itp){
  243    struct n_string s;
  244    int *msgvec, *ip;
  245    enum{a_NONE, a_SQUEEZE = 1u<<0,
  246       a_EMPTY = 1u<<8, a_STOP = 1u<<9,  a_WORKMASK = 0xFF00u} f;
  247    size_t tmax, plines;
  248    FILE *iobuf, *pbuf;
  249    NYD2_ENTER;
  250 
  251    if((iobuf = Ftmp(NULL, "topio", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
  252       n_perr(_("`top': I/O temporary file"), 0);
  253       vp = NULL;
  254       goto jleave;
  255    }
  256    if((pbuf = Ftmp(NULL, "toppag", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
  257       n_perr(_("`top': temporary pager file"), 0);
  258       vp = NULL;
  259       goto jleave1;
  260    }
  261 
  262    /* TODO In v15 we should query the m_message object, and directly send only
  263     * TODO those parts, optionally over empty-line-squeeze and quote-strip
  264     * TODO filters, in which we are interested in: only text content!
  265     * TODO And: with *topsqueeze*, header/content separating empty line.. */
  266    n_pstate &= ~n_PS_MSGLIST_DIRECT; /* TODO NO ATTACHMENTS */
  267    plines = 0;
  268 
  269    n_COLOUR( n_colour_env_create(n_COLOUR_CTX_VIEW, iobuf, FAL0); )
  270    n_string_creat_auto(&s);
  271    /* C99 */{
  272       siz_t l;
  273 
  274       if((n_idec_siz_cp(&l, ok_vlook(toplines), 0, NULL
  275                ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
  276             ) != n_IDEC_STATE_CONSUMED)
  277          l = 0;
  278       if(l <= 0){
  279          tmax = n_screensize();
  280          if(l < 0){
  281             l = n_ABS(l);
  282             tmax >>= l;
  283          }
  284       }else
  285          tmax = (size_t)l;
  286    }
  287    f = ok_blook(topsqueeze) ? a_SQUEEZE : a_NONE;
  288 
  289    for(ip = msgvec = vp;
  290          *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip){
  291       struct message *mp;
  292 
  293       mp = &message[*ip - 1];
  294       touch(mp);
  295       setdot(mp);
  296       n_pstate |= n_PS_DID_PRINT_DOT;
  297       uncollapse1(mp, 1);
  298 
  299       rewind(iobuf);
  300       if(ftruncate(fileno(iobuf), 0)){
  301          n_perr(_("`top': ftruncate(2)"), 0);
  302          vp = NULL;
  303          break;
  304       }
  305 
  306       if(!a_cmsg_show_overview(iobuf, mp, *ip) ||
  307             sendmp(mp, iobuf, itp, NULL, SEND_TODISP_ALL, NULL) < 0){
  308          n_err(_("`top': failed to prepare message %d\n"), *ip);
  309          vp = NULL;
  310          break;
  311       }
  312       fflush_rewind(iobuf);
  313 
  314       /* TODO Skip over the _msg_overview line -- this is a hack to make
  315        * TODO colours work: colour contexts should be objects */
  316       for(;;){
  317          int c;
  318 
  319          if((c = getc(iobuf)) == EOF || putc(c, pbuf) == EOF){
  320             vp = NULL;
  321             break;
  322          }else if(c == '\n')
  323             break;
  324       }
  325       if(vp == NULL)
  326          break;
  327       ++plines;
  328 
  329       /* C99 */{
  330          size_t l;
  331 
  332          n_string_trunc(&s, 0);
  333          for(l = 0, f &= ~a_WORKMASK; !(f & a_STOP);){
  334             int c;
  335 
  336             if((c = getc(iobuf)) == EOF){
  337                f |= a_STOP;
  338                c = '\n';
  339             }
  340 
  341             if(c != '\n')
  342                n_string_push_c(&s, c);
  343             else if((f & a_SQUEEZE) && s.s_len == 0){
  344                if(!(f & a_STOP) && ((f & a_EMPTY) || tmax - 1 <= l))
  345                   continue;
  346                if(putc('\n', pbuf) == EOF){
  347                   vp = NULL;
  348                   break;
  349                }
  350                f |= a_EMPTY;
  351                ++l;
  352             }else{
  353                char const *cp, *xcp;
  354 
  355                cp = n_string_cp_const(&s);
  356                /* TODO Brute simple skip part overviews; see above.. */
  357                if(!(f & a_SQUEEZE))
  358                   c = '\1';
  359                else if(s.s_len > 8 &&
  360                      (xcp = strstr(cp, "[-- ")) != NULL &&
  361                       strstr(&xcp[1], " --]") != NULL)
  362                   c = '\0';
  363                else{
  364                   char const *qcp;
  365 
  366                   for(qcp = ok_vlook(quote_chars); (c = *cp) != '\0'; ++cp){
  367                      if(!asciichar(c))
  368                         break;
  369                      if(!blankspacechar(c)){
  370                         if(strchr(qcp, c) == NULL)
  371                            break;
  372                         c = '\0';
  373                         break;
  374                      }
  375                   }
  376                }
  377 
  378                if(c != '\0'){
  379                   if(fputs(n_string_cp_const(&s), pbuf) == EOF ||
  380                         putc('\n', pbuf) == EOF){
  381                      vp = NULL;
  382                      break;
  383                   }
  384                   if(++l >= tmax)
  385                      break;
  386                   f &= ~a_EMPTY;
  387                }else
  388                   f |= a_EMPTY;
  389                n_string_trunc(&s, 0);
  390             }
  391          }
  392          if(vp == NULL)
  393             break;
  394          if(l > 0)
  395             plines += l;
  396          else{
  397             if(!(f & a_EMPTY) && putc('\n', pbuf) == EOF){
  398                vp = NULL;
  399                break;
  400             }
  401             ++plines;
  402          }
  403       }
  404    }
  405 
  406    n_string_gut(&s);
  407    n_COLOUR( n_colour_env_gut(); )
  408 
  409    fflush(pbuf);
  410    page_or_print(pbuf, plines);
  411 
  412    Fclose(pbuf);
  413 jleave1:
  414    Fclose(iobuf);
  415 jleave:
  416    NYD2_LEAVE;
  417    return (vp != NULL);
  418 }
  419 
  420 static int
  421 delm(int *msgvec)
  422 {
  423    struct message *mp;
  424    int rv = -1, *ip, last;
  425    NYD_ENTER;
  426 
  427    last = 0;
  428    for (ip = msgvec; *ip != 0; ++ip) {
  429       mp = message + *ip - 1;
  430       touch(mp);
  431       mp->m_flag |= MDELETED | MTOUCH;
  432       mp->m_flag &= ~(MPRESERVE | MSAVED | MBOX);
  433       last = *ip;
  434    }
  435    if (last != 0) {
  436       setdot(message + last - 1);
  437       last = first(0, MDELETED);
  438       if (last != 0) {
  439          setdot(message + last - 1);
  440          rv = 0;
  441       } else {
  442          setdot(message);
  443       }
  444    }
  445    NYD_LEAVE;
  446    return rv;
  447 }
  448 
  449 FL int
  450 c_more(void *v)
  451 {
  452    int *msgvec = v, rv;
  453    NYD_ENTER;
  454 
  455    rv = _type1(msgvec, TRU1, TRU1, FAL0, FAL0, NULL, NULL);
  456    NYD_LEAVE;
  457    return rv;
  458 }
  459 
  460 FL int
  461 c_More(void *v)
  462 {
  463    int *msgvec = v, rv;
  464    NYD_ENTER;
  465 
  466    rv = _type1(msgvec, FAL0, TRU1, FAL0, FAL0, NULL, NULL);
  467    NYD_LEAVE;
  468    return rv;
  469 }
  470 
  471 FL int
  472 c_type(void *v)
  473 {
  474    int *msgvec = v, rv;
  475    NYD_ENTER;
  476 
  477    rv = _type1(msgvec, TRU1, FAL0, FAL0, FAL0, NULL, NULL);
  478    NYD_LEAVE;
  479    return rv;
  480 }
  481 
  482 FL int
  483 c_Type(void *v)
  484 {
  485    int *msgvec = v, rv;
  486    NYD_ENTER;
  487 
  488    rv = _type1(msgvec, FAL0, FAL0, FAL0, FAL0, NULL, NULL);
  489    NYD_LEAVE;
  490    return rv;
  491 }
  492 
  493 FL int
  494 c_show(void *v)
  495 {
  496    int *msgvec = v, rv;
  497    NYD_ENTER;
  498 
  499    rv = _type1(msgvec, FAL0, FAL0, FAL0, TRU1, NULL, NULL);
  500    NYD_LEAVE;
  501    return rv;
  502 }
  503 
  504 FL int
  505 c_mimeview(void *vp){ /* TODO direct addressable parts, multiple such */
  506    struct message *mp;
  507    int rv, *msgvec;
  508    NYD_ENTER;
  509 
  510    if((msgvec = vp)[1] != 0){
  511       n_err(_("`mimeview': can yet only take one message, sorry!\n"));/* TODO */
  512       n_pstate_err_no = n_ERR_NOTSUP;
  513       rv = 1;
  514       goto jleave;
  515    }
  516 
  517    mp = &message[*msgvec - 1];
  518    touch(mp);
  519    setdot(mp);
  520    n_pstate |= n_PS_DID_PRINT_DOT;
  521    uncollapse1(mp, 1);
  522 
  523    n_COLOUR(
  524       n_colour_env_create(n_COLOUR_CTX_VIEW, n_stdout, FAL0);
  525    )
  526 
  527    if(!a_cmsg_show_overview(n_stdout, mp, *msgvec))
  528       n_pstate_err_no = n_ERR_IO;
  529    else if(sendmp(mp, n_stdout, n_IGNORE_TYPE, NULL, SEND_TODISP_PARTS,
  530          NULL) < 0)
  531       n_pstate_err_no = n_ERR_IO;
  532    else
  533       n_pstate_err_no = n_ERR_NONE;
  534 
  535    n_COLOUR(
  536       n_colour_env_gut();
  537    )
  538 
  539    rv = (n_pstate_err_no != n_ERR_NONE);
  540 jleave:
  541    NYD_LEAVE;
  542    return rv;
  543 }
  544 
  545 FL int
  546 c_pipe(void *v)
  547 {
  548    char *str = v;
  549    int rv;
  550    NYD_ENTER;
  551 
  552    rv = _pipe1(str, 1);
  553    NYD_LEAVE;
  554    return rv;
  555 }
  556 
  557 FL int
  558 c_Pipe(void *v)
  559 {
  560    char *str = v;
  561    int rv;
  562    NYD_ENTER;
  563 
  564    rv = _pipe1(str, 0);
  565    NYD_LEAVE;
  566    return rv;
  567 }
  568 
  569 FL int
  570 c_top(void *v){
  571    struct n_ignore *itp;
  572    int rv;
  573    NYD_ENTER;
  574 
  575    if(n_ignore_is_any(n_IGNORE_TOP))
  576       itp = n_IGNORE_TOP;
  577    else{
  578       itp = n_ignore_new(TRU1);
  579       n_ignore_insert(itp, TRU1, "from", sizeof("from") -1);
  580       n_ignore_insert(itp, TRU1, "to", sizeof("to") -1);
  581       n_ignore_insert(itp, TRU1, "cc", sizeof("cc") -1);
  582       n_ignore_insert(itp, TRU1, "subject", sizeof("subject") -1);
  583    }
  584 
  585    rv = !a_cmsg_top(v, itp);
  586    NYD_LEAVE;
  587    return rv;
  588 }
  589 
  590 FL int
  591 c_Top(void *v){
  592    int rv;
  593    NYD_ENTER;
  594 
  595    rv = !a_cmsg_top(v, n_IGNORE_TYPE);
  596    NYD_LEAVE;
  597    return rv;
  598 }
  599 
  600 FL int
  601 c_next(void *v)
  602 {
  603    int list[2], *ip, *ip2, mdot, *msgvec = v, rv = 1;
  604    struct message *mp;
  605    NYD_ENTER;
  606 
  607    if (*msgvec != 0) {
  608       /* If some messages were supplied, find the first applicable one
  609        * following dot using wrap around */
  610       mdot = (int)PTR2SIZE(dot - message + 1);
  611 
  612       /* Find first message in supplied message list which follows dot */
  613       for (ip = msgvec; *ip != 0; ++ip) {
  614          if ((mb.mb_threaded ? message[*ip - 1].m_threadpos > dot->m_threadpos
  615                : *ip > mdot))
  616             break;
  617       }
  618       if (*ip == 0)
  619          ip = msgvec;
  620       ip2 = ip;
  621       do {
  622          mp = message + *ip2 - 1;
  623          if (!(mp->m_flag & MMNDEL)) {
  624             setdot(mp);
  625             goto jhitit;
  626          }
  627          if (*ip2 != 0)
  628             ++ip2;
  629          if (*ip2 == 0)
  630             ip2 = msgvec;
  631       } while (ip2 != ip);
  632       fprintf(n_stdout, _("No messages applicable\n"));
  633       goto jleave;
  634    }
  635 
  636    /* If this is the first command, select message 1.  Note that this must
  637     * exist for us to get here at all */
  638    if (!(n_pstate & n_PS_SAW_COMMAND)) {
  639       if (msgCount == 0)
  640          goto jateof;
  641       goto jhitit;
  642    }
  643 
  644    /* Just find the next good message after dot, no wraparound */
  645    if (mb.mb_threaded == 0) {
  646       for (mp = dot + !!(n_pstate & n_PS_DID_PRINT_DOT);
  647             PTRCMP(mp, <, message + msgCount); ++mp)
  648          if (!(mp->m_flag & MMNORM))
  649             break;
  650    } else {
  651       /* TODO The threading code had some bugs that caused crashes.
  652        * TODO The last thing (before the deep look) happens here,
  653        * TODO so let's not trust n_PS_DID_PRINT_DOT but check & hope it fixes */
  654       if ((mp = dot) != NULL && (n_pstate & n_PS_DID_PRINT_DOT))
  655          mp = next_in_thread(mp);
  656       while (mp != NULL && (mp->m_flag & MMNORM))
  657          mp = next_in_thread(mp);
  658    }
  659    if (mp == NULL || PTRCMP(mp, >=, message + msgCount)) {
  660 jateof:
  661       fprintf(n_stdout, _("At EOF\n"));
  662       rv = 0;
  663       goto jleave;
  664    }
  665    setdot(mp);
  666 
  667    /* Print dot */
  668 jhitit:
  669    list[0] = (int)PTR2SIZE(dot - message + 1);
  670    list[1] = 0;
  671    rv = c_type(list);
  672 jleave:
  673    NYD_LEAVE;
  674    return rv;
  675 }
  676 
  677 FL int
  678 c_pdot(void *vp)
  679 {
  680    NYD_ENTER;
  681    n_UNUSED(vp);
  682    fprintf(n_stdout, "%d\n", (int)PTR2SIZE(dot - message + 1));
  683    NYD_LEAVE;
  684    return 0;
  685 }
  686 
  687 FL int
  688 c_messize(void *v)
  689 {
  690    int *msgvec = v, *ip, mesg;
  691    struct message *mp;
  692    NYD_ENTER;
  693 
  694    for (ip = msgvec; *ip != 0; ++ip) {
  695       mesg = *ip;
  696       mp = message + mesg - 1;
  697       fprintf(n_stdout, "%d: ", mesg);
  698       if (mp->m_xlines > 0)
  699          fprintf(n_stdout, "%ld", mp->m_xlines);
  700       else
  701          putc(' ', n_stdout);
  702       fprintf(n_stdout, "/%lu\n", (ul_i)mp->m_xsize);
  703    }
  704    NYD_LEAVE;
  705    return 0;
  706 }
  707 
  708 FL int
  709 c_delete(void *v)
  710 {
  711    int *msgvec = v;
  712    NYD_ENTER;
  713 
  714    delm(msgvec);
  715    NYD_LEAVE;
  716    return 0;
  717 }
  718 
  719 FL int
  720 c_deltype(void *v)
  721 {
  722    int list[2], rv = 0, *msgvec = v, lastdot;
  723    NYD_ENTER;
  724 
  725    lastdot = (int)PTR2SIZE(dot - message + 1);
  726    if (delm(msgvec) >= 0) {
  727       list[0] = (int)PTR2SIZE(dot - message + 1);
  728       if (list[0] > lastdot) {
  729          touch(dot);
  730          list[1] = 0;
  731          rv = c_type(list);
  732          goto jleave;
  733       }
  734       fprintf(n_stdout, _("At EOF\n"));
  735    } else
  736       fprintf(n_stdout, _("No more messages\n"));
  737 jleave:
  738    NYD_LEAVE;
  739    return rv;
  740 }
  741 
  742 FL int
  743 c_undelete(void *v)
  744 {
  745    int *msgvec = v, *ip;
  746    struct message *mp;
  747    NYD_ENTER;
  748 
  749    for (ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
  750          ++ip) {
  751       mp = &message[*ip - 1];
  752       touch(mp);
  753       setdot(mp);
  754       if (mp->m_flag & (MDELETED | MSAVED))
  755          mp->m_flag &= ~(MDELETED | MSAVED);
  756       else
  757          mp->m_flag &= ~MDELETED;
  758 #ifdef HAVE_IMAP
  759       if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
  760          imap_undelete(mp, *ip);
  761 #endif
  762    }
  763    NYD_LEAVE;
  764    return 0;
  765 }
  766 
  767 FL int
  768 c_stouch(void *v)
  769 {
  770    int *msgvec = v, *ip;
  771    NYD_ENTER;
  772 
  773    for (ip = msgvec; *ip != 0; ++ip) {
  774       setdot(message + *ip - 1);
  775       dot->m_flag |= MTOUCH;
  776       dot->m_flag &= ~MPRESERVE;
  777       n_pstate |= n_PS_DID_PRINT_DOT;
  778    }
  779    NYD_LEAVE;
  780    return 0;
  781 }
  782 
  783 FL int
  784 c_mboxit(void *v)
  785 {
  786    int *msgvec = v, *ip;
  787    NYD_ENTER;
  788 
  789    if (n_pstate & n_PS_EDIT) {
  790       n_err(_("`mbox' can only be used in a system mailbox\n")); /* TODO */
  791       goto jleave;
  792    }
  793 
  794    for (ip = msgvec; *ip != 0; ++ip) {
  795       setdot(message + *ip - 1);
  796       dot->m_flag |= MTOUCH | MBOX;
  797       dot->m_flag &= ~MPRESERVE;
  798       n_pstate |= n_PS_DID_PRINT_DOT;
  799    }
  800 jleave:
  801    NYD_LEAVE;
  802    return 0;
  803 }
  804 
  805 FL int
  806 c_preserve(void *v)
  807 {
  808    int *msgvec = v, *ip, mesg, rv = 1;
  809    struct message *mp;
  810    NYD_ENTER;
  811 
  812    if (n_pstate & n_PS_EDIT) {
  813       fprintf(n_stdout, _("Cannot `preserve' in a system mailbox\n"));
  814       goto jleave;
  815    }
  816 
  817    for (ip = msgvec; *ip != 0; ++ip) {
  818       mesg = *ip;
  819       mp = message + mesg - 1;
  820       mp->m_flag |= MPRESERVE;
  821       mp->m_flag &= ~MBOX;
  822       setdot(mp);
  823       n_pstate |= n_PS_DID_PRINT_DOT;
  824    }
  825    rv = 0;
  826 jleave:
  827    NYD_LEAVE;
  828    return rv;
  829 }
  830 
  831 FL int
  832 c_unread(void *v)
  833 {
  834    struct message *mp;
  835    int *msgvec = v, *ip;
  836    NYD_ENTER;
  837 
  838    for (ip = msgvec; *ip != 0; ++ip) {
  839       mp = &message[*ip - 1];
  840       setdot(mp);
  841       dot->m_flag &= ~(MREAD | MTOUCH);
  842       dot->m_flag |= MSTATUS;
  843 #ifdef HAVE_IMAP
  844       if (mb.mb_type == MB_IMAP || mb.mb_type == MB_CACHE)
  845          imap_unread(mp, *ip); /* TODO return? */
  846 #endif
  847       n_pstate |= n_PS_DID_PRINT_DOT;
  848    }
  849    NYD_LEAVE;
  850    return 0;
  851 }
  852 
  853 FL int
  854 c_seen(void *v)
  855 {
  856    int *msgvec = v, *ip;
  857    NYD_ENTER;
  858 
  859    for (ip = msgvec; *ip != 0; ++ip) {
  860       struct message *mp = message + *ip - 1;
  861       setdot(mp);
  862       touch(mp);
  863    }
  864    NYD_LEAVE;
  865    return 0;
  866 }
  867 
  868 FL int
  869 c_flag(void *v)
  870 {
  871    struct message *m;
  872    int *msgvec = v, *ip;
  873    NYD_ENTER;
  874 
  875    for (ip = msgvec; *ip != 0; ++ip) {
  876       m = message + *ip - 1;
  877       setdot(m);
  878       if (!(m->m_flag & (MFLAG | MFLAGGED)))
  879          m->m_flag |= MFLAG | MFLAGGED;
  880    }
  881    NYD_LEAVE;
  882    return 0;
  883 }
  884 
  885 FL int
  886 c_unflag(void *v)
  887 {
  888    struct message *m;
  889    int *msgvec = v, *ip;
  890    NYD_ENTER;
  891 
  892    for (ip = msgvec; *ip != 0; ++ip) {
  893       m = message + *ip - 1;
  894       setdot(m);
  895       if (m->m_flag & (MFLAG | MFLAGGED)) {
  896          m->m_flag &= ~(MFLAG | MFLAGGED);
  897          m->m_flag |= MUNFLAG;
  898       }
  899    }
  900    NYD_LEAVE;
  901    return 0;
  902 }
  903 
  904 FL int
  905 c_answered(void *v)
  906 {
  907    struct message *m;
  908    int *msgvec = v, *ip;
  909    NYD_ENTER;
  910 
  911    for (ip = msgvec; *ip != 0; ++ip) {
  912       m = message + *ip - 1;
  913       setdot(m);
  914       if (!(m->m_flag & (MANSWER | MANSWERED)))
  915          m->m_flag |= MANSWER | MANSWERED;
  916    }
  917    NYD_LEAVE;
  918    return 0;
  919 }
  920 
  921 FL int
  922 c_unanswered(void *v)
  923 {
  924    struct message *m;
  925    int *msgvec = v, *ip;
  926    NYD_ENTER;
  927 
  928    for (ip = msgvec; *ip != 0; ++ip) {
  929       m = message + *ip - 1;
  930       setdot(m);
  931       if (m->m_flag & (MANSWER | MANSWERED)) {
  932          m->m_flag &= ~(MANSWER | MANSWERED);
  933          m->m_flag |= MUNANSWER;
  934       }
  935    }
  936    NYD_LEAVE;
  937    return 0;
  938 }
  939 
  940 FL int
  941 c_draft(void *v)
  942 {
  943    struct message *m;
  944    int *msgvec = v, *ip;
  945    NYD_ENTER;
  946 
  947    for (ip = msgvec; *ip != 0; ++ip) {
  948       m = message + *ip - 1;
  949       setdot(m);
  950       if (!(m->m_flag & (MDRAFT | MDRAFTED)))
  951          m->m_flag |= MDRAFT | MDRAFTED;
  952    }
  953    NYD_LEAVE;
  954    return 0;
  955 }
  956 
  957 FL int
  958 c_undraft(void *v)
  959 {
  960    struct message *m;
  961    int *msgvec = v, *ip;
  962    NYD_ENTER;
  963 
  964    for (ip = msgvec; *ip != 0; ++ip) {
  965       m = message + *ip - 1;
  966       setdot(m);
  967       if (m->m_flag & (MDRAFT | MDRAFTED)) {
  968          m->m_flag &= ~(MDRAFT | MDRAFTED);
  969          m->m_flag |= MUNDRAFT;
  970       }
  971    }
  972    NYD_LEAVE;
  973    return 0;
  974 }
  975 
  976 /* s-it-mode */