"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/cmd-resend.c" (25 Mar 2018, 26530 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 "cmd-resend.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 14.9.7_vs_14.9.8.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ All sorts of `reply', `resend', `forward', and similar 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_resend
   37 
   38 #ifndef HAVE_AMALGAMATION
   39 # include "nail.h"
   40 #endif
   41 
   42 /* Modify subject we reply to to begin with Re: if it does not already */
   43 static char *a_crese_reedit(char const *subj);
   44 
   45 /* Fetch these headers, as appropriate */
   46 static struct name *a_crese_reply_to(struct message *mp);
   47 static struct name *a_crese_mail_followup_to(struct message *mp);
   48 
   49 /* We honoured Reply-To: and/or Mail-Followup-To:, but *recipients-in-cc* is
   50  * set so try to keep "secondary" addressees in Cc:, if possible, */
   51 static void a_crese_polite_rt_mft_move(struct message *mp, struct header *hp,
   52                      struct name *np);
   53 
   54 /* References and charset, as appropriate */
   55 static void a_crese_make_ref_and_cs(struct message *mp, struct header *head);
   56 
   57 /* `reply' and `Lreply' workhorse */
   58 static int a_crese_list_reply(int *msgvec, enum header_flags hf);
   59 
   60 /* Get PTF to implementation of command c (i.e., take care for *flipr*) */
   61 static int (*a_crese_reply_or_Reply(char c))(int *, bool_t);
   62 
   63 /* Reply to a single message.  Extract each name from the message header and
   64  * send them off to mail1() */
   65 static int a_crese_reply(int *msgvec, bool_t recipient_record);
   66 
   67 /* Reply to a series of messages by simply mailing to the senders and not
   68  * messing around with the To: and Cc: lists as in normal reply */
   69 static int a_crese_Reply(int *msgvec, bool_t recipient_record);
   70 
   71 /* Forward a message to a new recipient, in the sense of RFC 2822 */
   72 static int a_crese_fwd(char *str, int recipient_record);
   73 
   74 /* Modify the subject we are replying to to begin with Fwd: */
   75 static char *a_crese__fwdedit(char *subj);
   76 
   77 /* Do the real work of resending */
   78 static int a_crese_resend1(void *v, bool_t add_resent);
   79 
   80 static char *
   81 a_crese_reedit(char const *subj){
   82    char *newsubj;
   83    NYD2_ENTER;
   84 
   85    newsubj = NULL;
   86 
   87    if(subj != NULL && *subj != '\0'){
   88       struct str in, out;
   89       size_t i;
   90       char const *cp;
   91 
   92       in.l = strlen(in.s = n_UNCONST(subj));
   93       mime_fromhdr(&in, &out, TD_ISPR | TD_ICONV);
   94 
   95       i = strlen(cp = subject_re_trim(out.s)) +1;
   96       /* RFC mandates english "Re: " */
   97       newsubj = n_autorec_alloc(sizeof("Re: ") -1 + i);
   98       memcpy(newsubj, "Re: ", sizeof("Re: ") -1);
   99       memcpy(&newsubj[sizeof("Re: ") -1], cp, i);
  100 
  101       free(out.s);
  102    }
  103    NYD2_LEAVE;
  104    return newsubj;
  105 }
  106 
  107 static struct name *
  108 a_crese_reply_to(struct message *mp){
  109    char const *cp, *cp2;
  110    struct name *rt, *np;
  111    enum gfield gf;
  112    NYD2_ENTER;
  113 
  114    gf = ok_blook(fullnames) ? GFULL | GSKIN : GSKIN;
  115    rt = NULL;
  116 
  117    if((cp = ok_vlook(reply_to_honour)) != NULL &&
  118          (cp2 = hfield1("reply-to", mp)) != NULL &&
  119          (rt = checkaddrs(lextract(cp2, GTO | gf), EACM_STRICT, NULL)) != NULL){
  120       char *sp;
  121       size_t l;
  122       char const *tr;
  123 
  124       if((n_psonce & n_PSO_INTERACTIVE) && !(n_pstate & n_PS_ROBOT)){
  125          fprintf(n_stdout, _("Reply-To: header contains:"));
  126          for(np = rt; np != NULL; np = np->n_flink)
  127             fprintf(n_stdout, " %s", np->n_name);
  128          putc('\n', n_stdout);
  129       }
  130 
  131       tr = _("Reply-To %s%s");
  132       l = strlen(tr) + strlen(rt->n_name) + 3 +1;
  133       sp = n_lofi_alloc(l);
  134 
  135       snprintf(sp, l, tr, rt->n_name, (rt->n_flink != NULL ? "..." : n_empty));
  136       if(n_quadify(cp, UIZ_MAX, sp, TRU1) <= FAL0)
  137          rt = NULL;
  138 
  139       n_lofi_free(sp);
  140    }
  141    NYD2_LEAVE;
  142    return rt;
  143 }
  144 
  145 static struct name *
  146 a_crese_mail_followup_to(struct message *mp){
  147    char const *cp, *cp2;
  148    struct name *mft, *np;
  149    enum gfield gf;
  150    NYD2_ENTER;
  151 
  152    gf = ok_blook(fullnames) ? GFULL | GSKIN : GSKIN;
  153    mft = NULL;
  154 
  155    if((cp = ok_vlook(followup_to_honour)) != NULL &&
  156          (cp2 = hfield1("mail-followup-to", mp)) != NULL &&
  157          (mft = checkaddrs(lextract(cp2, GTO | gf), EACM_STRICT,NULL)) != NULL){
  158       char *sp;
  159       size_t l;
  160       char const *tr;
  161 
  162       if((n_psonce & n_PSO_INTERACTIVE) && !(n_pstate & n_PS_ROBOT)){
  163          fprintf(n_stdout, _("Mail-Followup-To: header contains:"));
  164          for(np = mft; np != NULL; np = np->n_flink)
  165             fprintf(n_stdout, " %s", np->n_name);
  166          putc('\n', n_stdout);
  167       }
  168 
  169       tr = _("Followup-To %s%s");
  170       l = strlen(tr) + strlen(mft->n_name) + 3 +1;
  171       sp = n_lofi_alloc(l);
  172 
  173       snprintf(sp, l, tr, mft->n_name,
  174          (mft->n_flink != NULL ? "..." : n_empty));
  175       if(n_quadify(cp, UIZ_MAX, sp, TRU1) <= FAL0)
  176          mft = NULL;
  177 
  178       n_lofi_free(sp);
  179    }
  180    NYD2_LEAVE;
  181    return mft;
  182 }
  183 
  184 static void
  185 a_crese_polite_rt_mft_move(struct message *mp, struct header *hp,
  186       struct name *np){
  187    bool_t once;
  188    NYD2_ENTER;
  189    n_UNUSED(mp);
  190 
  191    if(np == hp->h_to)
  192       hp->h_to = NULL;
  193    if(np == hp->h_cc)
  194       hp->h_cc = NULL;
  195 
  196    /* We may find that in the end To: is empty but Cc: is not, in which case we
  197     * upgrade Cc: to To:, and jump back and redo the thing slightly different */
  198    once = FAL0;
  199 jredo:
  200    while(np != NULL){
  201       enum gfield gf;
  202       struct name *nnp, **xpp, *xp;
  203 
  204       nnp = np;
  205       np = np->n_flink;
  206 
  207       if(once){
  208          gf = GTO;
  209          xpp = &hp->h_to;
  210       }else{
  211          gf = GCC;
  212          xpp = &hp->h_cc;
  213       }
  214 
  215       /* Try primary, then secondary */
  216       for(xp = hp->h_mailx_orig_to; xp != NULL; xp = xp->n_flink)
  217          if(!asccasecmp(xp->n_name, nnp->n_name))
  218             goto jlink;
  219 
  220       if(once){
  221          gf = GCC;
  222          xpp = &hp->h_cc;
  223       }
  224 
  225       for(xp = hp->h_mailx_orig_cc; xp != NULL; xp = xp->n_flink)
  226          if(!asccasecmp(xp->n_name, nnp->n_name))
  227             goto jlink;
  228 
  229       /* If this receiver came in only via R-T: or M-F-T:, place her/him/it in
  230        * To: due to lack of a better place */
  231       gf = GTO;
  232       xpp = &hp->h_to;
  233 jlink:
  234       /* Link it at the end to not loose original sort order */
  235       if((xp = *xpp) != NULL)
  236          while(xp->n_flink != NULL)
  237             xp = xp->n_flink;
  238 
  239       if((nnp->n_blink = xp) != NULL)
  240          xp->n_flink = nnp;
  241       else
  242          *xpp = nnp;
  243       nnp->n_flink = NULL;
  244       nnp->n_type = (nnp->n_type & ~GMASK) | gf;
  245    }
  246 
  247    /* If afterwards only Cc: data remains, upgrade all of it to To: */
  248    if(hp->h_to == NULL){
  249       np = hp->h_cc;
  250       hp->h_cc = NULL;
  251       if(!once){
  252          hp->h_to = NULL;
  253          once = TRU1;
  254          goto jredo;
  255       }else
  256          for(hp->h_to = np; np != NULL; np = np->n_flink)
  257             np->n_type = (np->n_type & ~GMASK) | GTO;
  258    }
  259    NYD2_LEAVE;
  260 }
  261 
  262 static void
  263 a_crese_make_ref_and_cs(struct message *mp, struct header *head) /* TODO ASAP */
  264 {
  265    char const *ccp;
  266    char *oldref, *oldmsgid, *newref;
  267    size_t oldreflen = 0, oldmsgidlen = 0, reflen;
  268    unsigned i;
  269    struct name *n;
  270    NYD2_ENTER;
  271 
  272    oldref = hfield1("references", mp);
  273    oldmsgid = hfield1("message-id", mp);
  274    if (oldmsgid == NULL || *oldmsgid == '\0') {
  275       head->h_ref = NULL;
  276       goto jleave;
  277    }
  278 
  279    reflen = 1;
  280    if (oldref) {
  281       oldreflen = strlen(oldref);
  282       reflen += oldreflen + 2;
  283    }
  284    if (oldmsgid) {
  285       oldmsgidlen = strlen(oldmsgid);
  286       reflen += oldmsgidlen;
  287    }
  288 
  289    newref = smalloc(reflen);
  290    if (oldref != NULL) {
  291       memcpy(newref, oldref, oldreflen +1);
  292       if (oldmsgid != NULL) {
  293          newref[oldreflen++] = ',';
  294          newref[oldreflen++] = ' ';
  295          memcpy(newref + oldreflen, oldmsgid, oldmsgidlen +1);
  296       }
  297    } else if (oldmsgid)
  298       memcpy(newref, oldmsgid, oldmsgidlen +1);
  299    n = extract(newref, GREF);
  300    free(newref);
  301 
  302    /* Limit number of references TODO better on parser side */
  303    while (n->n_flink != NULL)
  304       n = n->n_flink;
  305    for (i = 1; i <= REFERENCES_MAX; ++i) {
  306       if (n->n_blink != NULL)
  307          n = n->n_blink;
  308       else
  309          break;
  310    }
  311    n->n_blink = NULL;
  312    head->h_ref = n;
  313    if (ok_blook(reply_in_same_charset) &&
  314          (ccp = hfield1("content-type", mp)) != NULL){
  315       if((head->h_charset = ccp = mime_param_get("charset", ccp)) != NULL){
  316          if((ccp = n_iconv_normalize_name(ccp)) != NULL)
  317             ccp = n_charsetalias_expand(ccp);
  318          head->h_charset = ccp;
  319       }
  320    }
  321 jleave:
  322    NYD2_LEAVE;
  323 }
  324 
  325 static int
  326 a_crese_list_reply(int *msgvec, enum header_flags hf){
  327    struct header head;
  328    struct message *mp;
  329    char const *cp, *cp2;
  330    enum gfield gf;
  331    struct name *rt, *mft, *np;
  332    int *save_msgvec;
  333    NYD2_ENTER;
  334 
  335    n_pstate_err_no = n_ERR_NONE;
  336 
  337    /* TODO Since we may recur and do stuff with message lists we need to save
  338     * TODO away the argument vector as long as that isn't done by machinery */
  339    /* C99 */{
  340       size_t i;
  341       for(i = 0; msgvec[i] != 0; ++i)
  342          ;
  343       ++i;
  344       save_msgvec = n_lofi_alloc(sizeof(*save_msgvec) * i);
  345       while(i-- > 0)
  346          save_msgvec[i] = msgvec[i];
  347       msgvec = save_msgvec;
  348    }
  349 
  350    gf = ok_blook(fullnames) ? GFULL | GSKIN : GSKIN;
  351 
  352 jwork_msg:
  353    n_autorec_relax_create();
  354    mp = &message[*msgvec - 1];
  355    touch(mp);
  356    setdot(mp);
  357 
  358    memset(&head, 0, sizeof head);
  359    head.h_flags = hf;
  360    head.h_subject = a_crese_reedit(hfield1("subject", mp));
  361    head.h_mailx_command = (hf & HF_LIST_REPLY) ? "Lreply" : "reply";
  362    head.h_mailx_orig_from = lextract(hfield1("from", mp), GIDENT | gf);
  363    head.h_mailx_orig_to = lextract(hfield1("to", mp), GTO | gf);
  364    head.h_mailx_orig_cc = lextract(hfield1("cc", mp), GCC | gf);
  365    head.h_mailx_orig_bcc = lextract(hfield1("bcc", mp), GBCC | gf);
  366 
  367    /* First of all check for Reply-To: then Mail-Followup-To:, because these,
  368     * if honoured, take precedence over anything else.  We will join the
  369     * resulting list together if so desired.
  370     * So if we shall honour R-T: or M-F-T:, then these are our receivers! */
  371    rt = a_crese_reply_to(mp);
  372    mft = a_crese_mail_followup_to(mp);
  373 
  374    if(rt != NULL || mft != NULL){
  375       np = cat(rt, mft);
  376       if(mft != NULL)
  377          head.h_mft = namelist_dup(np, GTO | gf); /* xxx GTO: no "clone"! */
  378 
  379       /* Optionally do not propagate a receiver that originally was in
  380        * secondary Cc: to the primary To: list */
  381       if(ok_blook(recipients_in_cc)){
  382          a_crese_polite_rt_mft_move(mp, &head, np);
  383 
  384          head.h_mailx_raw_cc = namelist_dup(head.h_cc, GCC | gf);
  385          head.h_cc = n_alternates_remove(head.h_cc, FAL0);
  386       }else
  387          head.h_to = np;
  388 
  389       head.h_mailx_raw_to = namelist_dup(head.h_to, GTO | gf);
  390       head.h_to = n_alternates_remove(head.h_to, FAL0);
  391 #ifdef HAVE_DEVEL
  392       for(np = head.h_to; np != NULL; np = np->n_flink)
  393          assert((np->n_type & GMASK) == GTO);
  394       for(np = head.h_cc; np != NULL; np = np->n_flink)
  395          assert((np->n_type & GMASK) == GCC);
  396 #endif
  397       goto jrecipients_done;
  398    }
  399 
  400    /* Otherwise do the normal From: / To: / Cc: dance */
  401 
  402    if((cp2 = hfield1("from", mp)) == NULL)
  403       cp2 = nameof(mp, 1);
  404 
  405    /* Cc: */
  406    np = NULL;
  407    if(ok_blook(recipients_in_cc) && (cp = hfield1("to", mp)) != NULL)
  408       np = lextract(cp, GCC | gf);
  409    if((cp = hfield1("cc", mp)) != NULL){
  410       struct name *x;
  411 
  412       if((x = lextract(cp, GCC | gf)) != NULL)
  413          np = cat(np, x);
  414    }
  415    if(np != NULL){
  416       head.h_mailx_raw_cc = namelist_dup(np, GCC | gf);
  417       head.h_cc = n_alternates_remove(np, FAL0);
  418    }
  419 
  420    /* To: */
  421    np = NULL;
  422    if(cp2 != NULL)
  423       np = lextract(cp2, GTO | gf);
  424    if(!ok_blook(recipients_in_cc) && (cp = hfield1("to", mp)) != NULL){
  425       struct name *x;
  426 
  427       if((x = lextract(cp, GTO | gf)) != NULL)
  428          np = cat(np, x);
  429    }
  430    /* Delete my name from reply list, and with it, all my alternate names */
  431    if(np != NULL){
  432       head.h_mailx_raw_to = namelist_dup(np, GTO | gf);
  433       np = n_alternates_remove(np, FAL0);
  434       /* The user may have send this to himself, don't ignore that */
  435       if(count(np) == 0){
  436          np = lextract(cp2, GTO | gf);
  437          head.h_mailx_raw_to = namelist_dup(np, GTO | gf);
  438       }
  439    }
  440    head.h_to = np;
  441 
  442 jrecipients_done:
  443 
  444    /* For list replies we want to automatically recognize the list address
  445     * given in the List-Post: header, so that we will not throw away a possible
  446     * corresponding receiver: temporarily "`mlist' the List-Post: address" */
  447    if((hf & HF_LIST_REPLY) && (cp = hfield1("list-post", mp)) != NULL){
  448       struct name *x;
  449 
  450       if((x = lextract(cp, GEXTRA | GSKIN)) == NULL || x->n_flink != NULL ||
  451             (cp = url_mailto_to_address(x->n_name)) == NULL ||
  452             /* XXX terribly wasteful to create a new name, and can't we find
  453              * XXX a way to mitigate that?? */
  454             is_addr_invalid(x = nalloc(cp, GEXTRA | GSKIN), EACM_STRICT)){
  455          if(n_poption & n_PO_D_V)
  456             n_err(_("Message contains invalid List-Post: header\n"));
  457       }else{
  458          /* A special case has been seen on e.g. ietf-announce@ietf.org:
  459           * these usually post to multiple groups, with ietf-announce@
  460           * in List-Post:, but with Reply-To: set to ietf@ietf.org (since
  461           * -announce@ is only used for announcements, say).
  462           * So our desire is to honour this request and actively overwrite
  463           * List-Post: for our purpose; but only if its a single address.
  464           * However, to avoid ambiguities with users that place themselve in
  465           * Reply-To: and mailing lists which don't overwrite this (or only
  466           * extend this, shall such exist), only do so if reply_to exists of
  467           * a single address which points to the same domain as List-Post: */
  468          if(rt != NULL && rt->n_flink == NULL &&
  469                name_is_same_domain(x, rt))
  470             cp = rt->n_name; /* rt is EACM_STRICT tested */
  471          else
  472             cp = x->n_name;
  473 
  474          /* XXX is_mlist_mp()?? */
  475          if(is_mlist(cp, FAL0) == MLIST_OTHER)
  476             head.h_list_post = cp;
  477       }
  478    }
  479 
  480    /* In case of list replies we actively sort out any non-list recipient */
  481    if(hf & HF_LIST_REPLY){
  482       struct name **nhpp, *nhp, *tail;
  483 
  484       cp = head.h_list_post;
  485 
  486       nhp = *(nhpp = &head.h_to);
  487       head.h_to = NULL;
  488 j_lt_redo:
  489       for(tail = NULL; nhp != NULL;){
  490          np = nhp;
  491          nhp = nhp->n_flink;
  492 
  493          /* XXX is_mlist_mp()?? */
  494          if((cp != NULL && !asccasecmp(cp, np->n_name)) ||
  495                is_mlist(np->n_name, FAL0) != MLIST_OTHER){
  496             if((np->n_blink = tail) != NULL)
  497                tail->n_flink = np;
  498             else
  499                *nhpp = np;
  500             np->n_flink = NULL;
  501             tail = np;
  502          }
  503       }
  504       if(nhpp == &head.h_to){
  505          nhp = *(nhpp = &head.h_cc);
  506          head.h_cc = NULL;
  507          goto j_lt_redo;
  508       }
  509 
  510       /* For `Lreply' only, fail immediately with DESTADDRREQ if there are no
  511        * receivers at all! */
  512       if(head.h_to == NULL && head.h_cc == NULL){
  513          n_err(_("No recipients specified for `Lreply'\n"));
  514          if(msgvec[1] == 0){
  515             n_pstate_err_no = n_ERR_DESTADDRREQ;
  516             msgvec = NULL;
  517             goto jleave;
  518          }
  519          goto jskip_to_next;
  520       }
  521    }
  522 
  523    /* Move Cc: to To: as appropriate! */
  524    if(head.h_to == NULL && (np = head.h_cc) != NULL){
  525       head.h_cc = NULL;
  526       for(head.h_to = np; np != NULL; np = np->n_flink)
  527          np->n_type = (np->n_type & ~GMASK) | GTO;
  528    }
  529 
  530    a_crese_make_ref_and_cs(mp, &head);
  531 
  532    if(ok_blook(quote_as_attachment)){
  533       head.h_attach = csalloc(1, sizeof *head.h_attach);
  534       head.h_attach->a_msgno = *msgvec;
  535       head.h_attach->a_content_description = _("Original message content");
  536    }
  537 
  538    if(mail1(&head, 1, mp, NULL, !!(hf & HF_RECIPIENT_RECORD), 0) != OKAY){
  539       msgvec = NULL;
  540       goto jleave;
  541    }
  542    if(ok_blook(markanswered) && !(mp->m_flag & MANSWERED))
  543       mp->m_flag |= MANSWER | MANSWERED;
  544    n_autorec_relax_gut();
  545 
  546 jskip_to_next:
  547    if(*++msgvec != 0){
  548       /* TODO message (error) ring.., less sleep */
  549       if(n_psonce & n_PSO_INTERACTIVE){
  550          fprintf(n_stdout,
  551             _("Waiting a second before proceeding to the next message..\n"));
  552          fflush(n_stdout);
  553          n_msleep(1000, FAL0);
  554       }
  555       goto jwork_msg;
  556    }
  557 
  558 jleave:
  559    n_lofi_free(save_msgvec);
  560    NYD2_LEAVE;
  561    return (msgvec == NULL);
  562 }
  563 
  564 static int
  565 (*a_crese_reply_or_Reply(char c))(int *, bool_t){
  566    int (*rv)(int*, bool_t);
  567    NYD2_ENTER;
  568 
  569    rv = (ok_blook(flipr) ^ (c == 'R')) ? &a_crese_Reply : &a_crese_reply;
  570    NYD2_LEAVE;
  571    return rv;
  572 }
  573 
  574 static int
  575 a_crese_reply(int *msgvec, bool_t recipient_record){
  576    int rv;
  577    NYD2_ENTER;
  578 
  579    rv = a_crese_list_reply(msgvec,
  580          (recipient_record ? HF_RECIPIENT_RECORD : HF_NONE));
  581    NYD2_LEAVE;
  582    return rv;
  583 }
  584 
  585 static int
  586 a_crese_Reply(int *msgvec, bool_t recipient_record){
  587    struct header head;
  588    struct message *mp;
  589    int *ap;
  590    enum gfield gf;
  591    NYD2_ENTER;
  592 
  593    memset(&head, 0, sizeof head);
  594    gf = ok_blook(fullnames) ? GFULL | GSKIN : GSKIN;
  595 
  596    for(ap = msgvec; *ap != 0; ++ap){
  597       struct name *np;
  598 
  599       mp = &message[*ap - 1];
  600       touch(mp);
  601       setdot(mp);
  602 
  603       if((np = a_crese_reply_to(mp)) == NULL){
  604          char *cp;
  605 
  606          if((cp = hfield1("from", mp)) == NULL)
  607             cp = nameof(mp, 2);
  608          np = lextract(cp, GTO | gf);
  609       }
  610       head.h_to = cat(head.h_to, np);
  611    }
  612 
  613    mp = &message[msgvec[0] - 1];
  614    head.h_subject = hfield1("subject", mp);
  615    head.h_subject = a_crese_reedit(head.h_subject);
  616    a_crese_make_ref_and_cs(mp, &head);
  617    head.h_mailx_command = "Reply";
  618    head.h_mailx_orig_from = lextract(hfield1("from", mp), GIDENT | gf);
  619    head.h_mailx_orig_to = lextract(hfield1("to", mp), GTO | gf);
  620    head.h_mailx_orig_cc = lextract(hfield1("cc", mp), GCC | gf);
  621    head.h_mailx_orig_bcc = lextract(hfield1("bcc", mp), GBCC | gf);
  622 
  623    if(ok_blook(recipients_in_cc)){
  624       a_crese_polite_rt_mft_move(mp, &head, head.h_to);
  625 
  626       head.h_mailx_raw_cc = namelist_dup(head.h_cc, GCC | gf);
  627       head.h_cc = n_alternates_remove(head.h_cc, FAL0);
  628    }
  629    head.h_mailx_raw_to = namelist_dup(head.h_to, GTO | gf);
  630    head.h_to = n_alternates_remove(head.h_to, FAL0);
  631 
  632    if(ok_blook(quote_as_attachment)){
  633       head.h_attach = csalloc(1, sizeof *head.h_attach);
  634       head.h_attach->a_msgno = *msgvec;
  635       head.h_attach->a_content_description = _("Original message content");
  636    }
  637 
  638    if(mail1(&head, 1, mp, NULL, recipient_record, 0) != OKAY){
  639       msgvec = NULL;
  640       goto jleave;
  641    }
  642 
  643    if(ok_blook(markanswered) && !(mp->m_flag & MANSWERED))
  644       mp->m_flag |= MANSWER | MANSWERED;
  645 jleave:
  646    NYD2_LEAVE;
  647    return (msgvec == NULL);
  648 }
  649 
  650 static int
  651 a_crese_fwd(char *str, int recipient_record){
  652    struct header head;
  653    struct message *mp;
  654    enum gfield gf;
  655    bool_t f, forward_as_attachment;
  656    char *recipient;
  657    int rv, *msgvec;
  658    NYD2_ENTER;
  659 
  660    rv = 1;
  661 
  662    if((recipient = laststring(str, &f, TRU1)) == NULL){
  663       n_err(_("No recipient specified.\n"));
  664       n_pstate_err_no = n_ERR_DESTADDRREQ;
  665       goto jleave;
  666    }
  667 
  668    forward_as_attachment = ok_blook(forward_as_attachment);
  669    gf = ok_blook(fullnames) ? GFULL | GSKIN : GSKIN;
  670    msgvec = n_autorec_alloc((msgCount + 2) * sizeof *msgvec);
  671 
  672    n_pstate_err_no = n_ERR_NODATA;
  673    if(!f){
  674       *msgvec = first(0, MMNORM);
  675       if(*msgvec != 0)
  676          msgvec[1] = 0;
  677    }else if(getmsglist(str, msgvec, 0) < 0)
  678       goto jleave;
  679 
  680    if(*msgvec == 0){
  681       n_err(_("No applicable messages.\n"));
  682       goto jleave;
  683    }
  684    if(msgvec[1] != 0){
  685       n_err(_("Cannot forward multiple messages at once\n"));
  686       n_pstate_err_no = n_ERR_NOTSUP;
  687       goto jleave;
  688    }
  689 
  690    memset(&head, 0, sizeof head);
  691    head.h_to = lextract(recipient,
  692          (GTO | (ok_blook(fullnames) ? GFULL : GSKIN)));
  693 
  694    mp = &message[*msgvec - 1];
  695    touch(mp);
  696    setdot(mp);
  697    head.h_subject = hfield1("subject", mp);
  698    head.h_subject = a_crese__fwdedit(head.h_subject);
  699    head.h_mailx_command = "forward";
  700    head.h_mailx_raw_to = namelist_dup(head.h_to, GTO | gf);
  701    head.h_mailx_orig_from = lextract(hfield1("from", mp), GIDENT | gf);
  702    head.h_mailx_orig_to = lextract(hfield1("to", mp), GTO | gf);
  703    head.h_mailx_orig_cc = lextract(hfield1("cc", mp), GCC | gf);
  704    head.h_mailx_orig_bcc = lextract(hfield1("bcc", mp), GBCC | gf);
  705 
  706    if(forward_as_attachment){
  707       head.h_attach = csalloc(1, sizeof *head.h_attach);
  708       head.h_attach->a_msgno = *msgvec;
  709       head.h_attach->a_content_description = _("Forwarded message");
  710    }
  711 
  712    rv = (mail1(&head, 1, (forward_as_attachment ? NULL : mp), NULL,
  713          recipient_record, 1) != OKAY); /* reverse! */
  714 jleave:
  715    NYD2_LEAVE;
  716    return rv;
  717 }
  718 
  719 static char *
  720 a_crese__fwdedit(char *subj){
  721    struct str in, out;
  722    char *newsubj;
  723    NYD2_ENTER;
  724 
  725    newsubj = NULL;
  726 
  727    if(subj == NULL || *subj == '\0')
  728       goto jleave;
  729 
  730    in.s = subj;
  731    in.l = strlen(subj);
  732    mime_fromhdr(&in, &out, TD_ISPR | TD_ICONV);
  733 
  734    newsubj = n_autorec_alloc(out.l + 6);
  735    if(!ascncasecmp(out.s, "Fwd: ", sizeof("Fwd: ") -1)) /* TODO EXTEND SUPP.. */
  736       memcpy(newsubj, out.s, out.l +1);
  737    else{
  738       memcpy(newsubj, "Fwd: ", 5); /* TODO ..a la subject_re_trim()! */
  739       memcpy(&newsubj[5], out.s, out.l +1);
  740    }
  741 
  742    free(out.s);
  743 jleave:
  744    NYD2_LEAVE;
  745    return newsubj;
  746 }
  747 
  748 static int
  749 a_crese_resend1(void *vp, bool_t add_resent){
  750    struct header head;
  751    struct name *myto, *myrawto;
  752    enum gfield gf;
  753    char *name, *str;
  754    int *ip, *msgvec;
  755    bool_t fail;
  756    NYD2_ENTER;
  757 
  758    fail = TRU1;
  759 
  760    str = vp;
  761    msgvec = n_autorec_alloc((msgCount + 2) * sizeof *msgvec);
  762    name = laststring(str, &fail, TRU1);
  763    if(name == NULL){
  764       n_err(_("No recipient specified.\n"));
  765       n_pstate_err_no = n_ERR_DESTADDRREQ;
  766       goto jleave;
  767    }
  768 
  769    n_pstate_err_no = n_ERR_NODATA;
  770 
  771    if(!fail){
  772       *msgvec = first(0, MMNORM);
  773       if(*msgvec != 0)
  774          msgvec[1] = 0;
  775    }else if(getmsglist(str, msgvec, 0) < 0)
  776       goto jleave;
  777 
  778    if(*msgvec == 0){
  779       n_err(_("No applicable messages.\n"));
  780       goto jleave;
  781    }
  782 
  783    fail = TRU1;
  784    gf = ok_blook(fullnames) ? GFULL | GSKIN : GSKIN;
  785 
  786    myrawto = nalloc(name, GTO | gf);
  787    myto = usermap(namelist_dup(myrawto, myrawto->n_type), FAL0);
  788    myto = n_alternates_remove(myto, TRU1);
  789    if(myto == NULL){
  790       n_pstate_err_no = n_ERR_DESTADDRREQ;
  791       goto jleave;
  792    }
  793 
  794    n_autorec_relax_create();
  795    for(ip = msgvec; *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount);
  796          ++ip){
  797       struct message *mp;
  798 
  799       mp = &message[*ip - 1];
  800       touch(mp);
  801       setdot(mp);
  802 
  803       memset(&head, 0, sizeof head);
  804       head.h_to = myto;
  805       head.h_mailx_command = "resend";
  806       head.h_mailx_raw_to = myrawto;
  807       head.h_mailx_orig_from = lextract(hfield1("from", mp), GIDENT | gf);
  808       head.h_mailx_orig_to = lextract(hfield1("to", mp), GTO | gf);
  809       head.h_mailx_orig_cc = lextract(hfield1("cc", mp), GCC | gf);
  810       head.h_mailx_orig_bcc = lextract(hfield1("bcc", mp), GBCC | gf);
  811 
  812       if(resend_msg(mp, &head, add_resent) != OKAY){
  813          /* n_autorec_relax_gut(); XXX but is handled automatically? */
  814          goto jleave;
  815       }
  816       n_autorec_relax_unroll();
  817    }
  818    n_autorec_relax_gut();
  819 
  820    fail = FAL0;
  821    n_pstate_err_no = n_ERR_NONE;
  822 jleave:
  823    NYD2_LEAVE;
  824    return (fail != FAL0);
  825 }
  826 
  827 FL int
  828 c_reply(void *vp){
  829    int rv;
  830    NYD_ENTER;
  831 
  832    rv = (*a_crese_reply_or_Reply('r'))(vp, FAL0);
  833    NYD_LEAVE;
  834    return rv;
  835 }
  836 
  837 FL int
  838 c_replyall(void *vp){
  839    int rv;
  840    NYD_ENTER;
  841 
  842    rv = a_crese_reply(vp, FAL0);
  843    NYD_LEAVE;
  844    return rv;
  845 }
  846 
  847 FL int
  848 c_replysender(void *vp){
  849    int rv;
  850    NYD_ENTER;
  851 
  852    rv = a_crese_Reply(vp, FAL0);
  853    NYD_LEAVE;
  854    return rv;
  855 }
  856 
  857 FL int
  858 c_Reply(void *vp){
  859    int rv;
  860    NYD_ENTER;
  861 
  862    rv = (*a_crese_reply_or_Reply('R'))(vp, FAL0);
  863    NYD_LEAVE;
  864    return rv;
  865 }
  866 
  867 FL int
  868 c_Lreply(void *vp){
  869    int rv;
  870    NYD_ENTER;
  871 
  872    rv = a_crese_list_reply(vp, HF_LIST_REPLY);
  873    NYD_LEAVE;
  874    return rv;
  875 }
  876 
  877 FL int
  878 c_followup(void *vp){
  879    int rv;
  880    NYD_ENTER;
  881 
  882    rv = (*a_crese_reply_or_Reply('r'))(vp, TRU1);
  883    NYD_LEAVE;
  884    return rv;
  885 }
  886 
  887 FL int
  888 c_followupall(void *vp){
  889    int rv;
  890    NYD_ENTER;
  891 
  892    rv = a_crese_reply(vp, TRU1);
  893    NYD_LEAVE;
  894    return rv;
  895 }
  896 
  897 FL int
  898 c_followupsender(void *vp){
  899    int rv;
  900    NYD_ENTER;
  901 
  902    rv = a_crese_Reply(vp, TRU1);
  903    NYD_LEAVE;
  904    return rv;
  905 }
  906 
  907 FL int
  908 c_Followup(void *vp){
  909    int rv;
  910    NYD_ENTER;
  911 
  912    rv = (*a_crese_reply_or_Reply('R'))(vp, TRU1);
  913    NYD_LEAVE;
  914    return rv;
  915 }
  916 
  917 FL int
  918 c_forward(void *vp){
  919    int rv;
  920    NYD_ENTER;
  921 
  922    rv = a_crese_fwd(vp, 0);
  923    NYD_LEAVE;
  924    return rv;
  925 }
  926 
  927 FL int
  928 c_Forward(void *vp){
  929    int rv;
  930    NYD_ENTER;
  931 
  932    rv = a_crese_fwd(vp, 1);
  933    NYD_LEAVE;
  934    return rv;
  935 }
  936 
  937 FL int
  938 c_resend(void *vp){
  939    int rv;
  940    NYD_ENTER;
  941 
  942    rv = a_crese_resend1(vp, TRU1);
  943    NYD_LEAVE;
  944    return rv;
  945 }
  946 
  947 FL int
  948 c_Resend(void *vp){
  949    int rv;
  950    NYD_ENTER;
  951 
  952    rv = a_crese_resend1(vp, FAL0);
  953    NYD_LEAVE;
  954    return rv;
  955 }
  956 
  957 /* s-it-mode */