make-config.in: complete path (leftover of [807f64e2], 2015-12-26!)
[s-mailx.git] / dig-msg.c
blobf61e8a7bf014c2525072223dcb40d223660120f6
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Dig message objects. TODO Very very restricted (especially non-compose)
3 *@ On protocol change adjust config.h:n_DIG_MSG_PLUMBING_VERSION + `~^' manual
4 *@ TODO - a_dmsg_cmd() should generate string lists, not perform real I/O.
5 *@ TODO I.e., drop FILE* arg, generate stringlist; up to callers...
6 *@ TODO - With our own I/O there should then be a StringListDevice as the
7 *@ TODO owner and I/O overlay provider: NO temporary file (sic)!
8 *@ XXX - Multiple objects per message could be possible (a_dmsg_find()),
9 *@ XXX except in compose mode
11 * Copyright (c) 2016 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
12 * SPDX-License-Identifier: ISC
14 * Permission to use, copy, modify, and/or distribute this software for any
15 * purpose with or without fee is hereby granted, provided that the above
16 * copyright notice and this permission notice appear in all copies.
18 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
19 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
21 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
23 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
24 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 #undef n_FILE
27 #define n_FILE dig_msg
29 #ifndef HAVE_AMALGAMATION
30 # include "nail.h"
31 #endif
33 /* Try to convert cp into an unsigned number that corresponds to an existing
34 * message number (or ERR_INVAL), search for an existing object (ERR_EXIST if
35 * oexcl and exists; ERR_NOENT if not oexcl and does not exist).
36 * On oexcl success *dmcp will be n_alloc()ated with .dmc_msgno and .dmc_mp
37 * etc. set; but not linked into mb.mb_digmsg and .dmc_fp not created etc. */
38 static si32_t a_dmsg_find(char const *cp, struct n_dig_msg_ctx **dmcpp,
39 bool_t oexcl);
41 /* Subcommand drivers */
42 static bool_t a_dmsg_cmd(FILE *fp, struct n_dig_msg_ctx *dmcp, char const *cmd,
43 uiz_t cmdl, char const *cp);
45 static bool_t a_dmsg__header(FILE *fp, struct n_dig_msg_ctx *dmcp,
46 char const *cmda[3]);
47 static bool_t a_dmsg__attach(FILE *fp, struct n_dig_msg_ctx *dmcp,
48 char const *cmda[3]);
50 static si32_t
51 a_dmsg_find(char const *cp, struct n_dig_msg_ctx **dmcpp, bool_t oexcl){
52 struct n_dig_msg_ctx *dmcp;
53 si32_t rv;
54 ui32_t msgno;
55 NYD2_IN;
57 if(cp[0] == '-' && cp[1] == '\0'){
58 if((dmcp = n_dig_msg_compose_ctx) != NULL){
59 *dmcpp = dmcp;
60 if(dmcp->dmc_flags & n_DIG_MSG_COMPOSE_DIGGED)
61 rv = oexcl ? n_ERR_EXIST : n_ERR_NONE;
62 else
63 rv = oexcl ? n_ERR_NONE : n_ERR_NOENT;
64 }else
65 rv = n_ERR_INVAL;
66 goto jleave;
69 if((n_idec_ui32_cp(&msgno, cp, 0, NULL
70 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
71 ) != n_IDEC_STATE_CONSUMED ||
72 msgno == 0 || UICMP(z, msgno, >, msgCount)){
73 rv = n_ERR_INVAL;
74 goto jleave;
77 for(dmcp = mb.mb_digmsg; dmcp != NULL; dmcp = dmcp->dmc_next)
78 if(dmcp->dmc_msgno == msgno){
79 *dmcpp = dmcp;
80 rv = oexcl ? n_ERR_EXIST : n_ERR_NONE;
81 goto jleave;
83 if(!oexcl){
84 rv = n_ERR_NOENT;
85 goto jleave;
88 *dmcpp = dmcp = n_calloc(1, n_ALIGN(sizeof *dmcp) + sizeof(struct header));
89 dmcp->dmc_mp = &message[msgno - 1];
90 dmcp->dmc_flags = n_DIG_MSG_OWN_MEMPOOL |
91 ((TRU1/*TODO*/ || !(mb.mb_perm & MB_DELE))
92 ? n_DIG_MSG_RDONLY : n_DIG_MSG_NONE);
93 dmcp->dmc_msgno = msgno;
94 dmcp->dmc_hp = (struct header*)n_ALIGN(PTR2SIZE(&dmcp[1]));
95 dmcp->dmc_mempool = dmcp->dmc_mempool_buf;
96 /* Rest done by caller */
97 rv = n_ERR_NONE;
98 jleave:
99 NYD2_OU;
100 return rv;
103 static bool_t
104 a_dmsg_cmd(FILE *fp, struct n_dig_msg_ctx *dmcp, char const *cmd, uiz_t cmdl,
105 char const *cp){
106 char const *cmda[3];
107 bool_t rv;
108 NYD2_IN;
110 /* C99 */{
111 size_t i;
113 /* TODO trim+strlist_split(_ifs?)() */
114 for(i = 0; i < n_NELEM(cmda); ++i){
115 while(blankchar(*cp))
116 ++cp;
117 if(*cp == '\0')
118 cmda[i] = NULL;
119 else{
120 if(i < n_NELEM(cmda) - 1)
121 for(cmda[i] = cp++; *cp != '\0' && !blankchar(*cp); ++cp)
123 else{
124 /* Last slot takes all the rest of the line, less trailing WS */
125 for(cmda[i] = cp++; *cp != '\0'; ++cp)
127 while(blankchar(cp[-1]))
128 --cp;
130 cmda[i] = savestrbuf(cmda[i], PTR2SIZE(cp - cmda[i]));
135 if(is_ascncaseprefix(cmd, "header", cmdl))
136 rv = a_dmsg__header(fp, dmcp, cmda);
137 else if(is_ascncaseprefix(cmd, "attachment", cmdl)){
138 if(!(dmcp->dmc_flags & n_DIG_MSG_COMPOSE)) /* TODO attachment support */
139 rv = (fprintf(fp,
140 "505 `digmsg attachment' only in compose mode (yet)\n") > 0);
141 else
142 rv = a_dmsg__attach(fp, dmcp, cmda);
143 }else if(is_ascncaseprefix(cmd, "version", cmdl)){
144 if(cmda[0] != NULL)
145 goto jecmd;
146 rv = (fputs("210 " n_DIG_MSG_PLUMBING_VERSION "\n", fp) != EOF);
147 }else{
148 jecmd:
149 fputs("500\n", fp);
150 rv = FAL0;
152 fflush(fp);
154 NYD2_OU;
155 return rv;
158 static bool_t
159 a_dmsg__header(FILE *fp, struct n_dig_msg_ctx *dmcp, char const *cmda[3]){
160 uiz_t i;
161 struct n_header_field *hfp;
162 struct name *np, **npp;
163 char const *cp;
164 struct header *hp;
165 NYD2_IN;
167 hp = dmcp->dmc_hp;
169 if((cp = cmda[0]) == NULL){
170 cp = n_empty; /* xxx not NULL anyway */
171 goto jdefault;
174 if(is_asccaseprefix(cp, "insert")){ /* TODO LOGIC BELONGS head.c
175 * TODO That is: Header::factory(string) -> object (blahblah).
176 * TODO I.e., as long as we don't have regular RFC compliant parsers
177 * TODO which differentiate in between structured and unstructured
178 * TODO header fields etc., a little workaround */
179 struct name *xnp;
180 si8_t aerr;
181 enum expand_addr_check_mode eacm;
182 enum gfield ntype;
183 bool_t mult_ok;
185 if(cmda[1] == NULL || cmda[2] == NULL)
186 goto jecmd;
187 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
188 goto j505r;
190 /* Strip [\r\n] which would render a body invalid XXX all controls? */
191 /* C99 */{
192 char *xp, c;
194 cmda[2] = xp = savestr(cmda[2]);
195 for(; (c = *xp) != '\0'; ++xp)
196 if(c == '\n' || c == '\r')
197 *xp = ' ';
200 if(!asccasecmp(cmda[1], cp = "Subject")){
201 if(cmda[2][0] != '\0'){
202 if(hp->h_subject != NULL)
203 hp->h_subject = savecatsep(hp->h_subject, ' ', cmda[2]);
204 else
205 hp->h_subject = n_UNCONST(cmda[2]);
206 if(fprintf(fp, "210 %s 1\n", cp) < 0)
207 cp = NULL;
208 goto jleave;
209 }else
210 goto j501cp;
213 mult_ok = TRU1;
214 ntype = GEXTRA | GFULL | GFULLEXTRA;
215 eacm = EACM_STRICT;
217 if(!asccasecmp(cmda[1], cp = "From")){
218 npp = &hp->h_from;
219 jins:
220 aerr = 0;
221 /* todo As said above, this should be table driven etc., but.. */
222 if(ntype & GBCC_IS_FCC){
223 np = nalloc_fcc(cmda[2]);
224 if(is_addr_invalid(np, eacm))
225 goto jins_505;
226 }else{
227 if((np = lextract(cmda[2], ntype)) == NULL)
228 goto j501cp;
230 if((np = checkaddrs(np, eacm, &aerr), aerr != 0)){
231 jins_505:
232 if(fprintf(fp, "505 %s\n", cp) < 0)
233 cp = NULL;
234 goto jleave;
238 /* Go to the end of the list, track whether it contains any
239 * non-deleted entries */
240 i = 0;
241 if((xnp = *npp) != NULL)
242 for(;; xnp = xnp->n_flink){
243 if(!(xnp->n_type & GDEL))
244 ++i;
245 if(xnp->n_flink == NULL)
246 break;
249 if(!mult_ok && (i != 0 || np->n_flink != NULL)){
250 if(fprintf(fp, "506 %s\n", cp) < 0)
251 cp = NULL;
252 }else{
253 if(xnp == NULL)
254 *npp = np;
255 else
256 xnp->n_flink = np;
257 np->n_blink = xnp;
258 if(fprintf(fp, "210 %s %" PRIuZ "\n", cp, ++i) < 0)
259 cp = NULL;
261 goto jleave;
263 if(!asccasecmp(cmda[1], cp = "Sender")){
264 mult_ok = FAL0;
265 npp = &hp->h_sender;
266 goto jins;
268 if(!asccasecmp(cmda[1], cp = "To")){
269 npp = &hp->h_to;
270 ntype = GTO | GFULL;
271 eacm = EACM_NORMAL | EAF_NAME;
272 goto jins;
274 if(!asccasecmp(cmda[1], cp = "Cc")){
275 npp = &hp->h_cc;
276 ntype = GCC | GFULL;
277 eacm = EACM_NORMAL | EAF_NAME;
278 goto jins;
280 if(!asccasecmp(cmda[1], cp = "Bcc")){
281 npp = &hp->h_bcc;
282 ntype = GBCC | GFULL;
283 eacm = EACM_NORMAL | EAF_NAME;
284 goto jins;
286 if(!asccasecmp(cmda[1], cp = "Fcc")){
287 npp = &hp->h_fcc;
288 ntype = GBCC | GBCC_IS_FCC;
289 eacm = EACM_NORMAL /* Not | EAF_FILE, depend on *expandaddr*! */;
290 goto jins;
292 if(!asccasecmp(cmda[1], cp = "Reply-To")){
293 npp = &hp->h_reply_to;
294 eacm = EACM_NONAME;
295 goto jins;
297 if(!asccasecmp(cmda[1], cp = "Mail-Followup-To")){
298 npp = &hp->h_mft;
299 eacm = EACM_NONAME;
300 goto jins;
302 if(!asccasecmp(cmda[1], cp = "Message-ID")){
303 mult_ok = FAL0;
304 npp = &hp->h_message_id;
305 ntype = GREF;
306 eacm = EACM_NONAME;
307 goto jins;
309 if(!asccasecmp(cmda[1], cp = "References")){
310 npp = &hp->h_ref;
311 ntype = GREF;
312 eacm = EACM_NONAME;
313 goto jins;
315 if(!asccasecmp(cmda[1], cp = "In-Reply-To")){
316 npp = &hp->h_in_reply_to;
317 ntype = GREF;
318 eacm = EACM_NONAME;
319 goto jins;
322 if((cp = n_header_is_known(cmda[1], UIZ_MAX)) != NULL)
323 goto j505r;
325 /* Free-form header fields */
326 /* C99 */{
327 size_t nl, bl;
328 struct n_header_field **hfpp;
330 for(cp = cmda[1]; *cp != '\0'; ++cp)
331 if(!fieldnamechar(*cp)){
332 cp = cmda[1];
333 goto j501cp;
336 for(i = 0, hfpp = &hp->h_user_headers; *hfpp != NULL; ++i)
337 hfpp = &(*hfpp)->hf_next;
339 nl = strlen(cp = cmda[1]) +1;
340 bl = strlen(cmda[2]) +1;
341 *hfpp = hfp = n_autorec_alloc(n_VSTRUCT_SIZEOF(struct n_header_field,
342 hf_dat) + nl + bl);
343 hfp->hf_next = NULL;
344 hfp->hf_nl = nl - 1;
345 hfp->hf_bl = bl - 1;
346 memcpy(&hfp->hf_dat[0], cp, nl);
347 memcpy(&hfp->hf_dat[nl], cmda[2], bl);
348 if(fprintf(fp, "210 %s %" PRIuZ "\n",
349 &hfp->hf_dat[0], ++i) < 0)
350 cp = NULL;
352 }else if(is_asccaseprefix(cp, "list")){
353 jdefault:
354 if(cmda[1] == NULL){
355 fputs("210", fp);
356 if(hp->h_subject != NULL) fputs(" Subject", fp);
357 if(hp->h_from != NULL) fputs(" From", fp);
358 if(hp->h_sender != NULL) fputs(" Sender", fp);
359 if(hp->h_to != NULL) fputs(" To", fp);
360 if(hp->h_cc != NULL) fputs(" Cc", fp);
361 if(hp->h_bcc != NULL) fputs(" Bcc", fp);
362 if(hp->h_fcc != NULL) fputs(" Fcc", fp);
363 if(hp->h_reply_to != NULL) fputs(" Reply-To", fp);
364 if(hp->h_mft != NULL) fputs(" Mail-Followup-To", fp);
365 if(hp->h_message_id != NULL) fputs(" Message-ID", fp);
366 if(hp->h_ref != NULL) fputs(" References", fp);
367 if(hp->h_in_reply_to != NULL) fputs(" In-Reply-To", fp);
368 if(hp->h_mailx_command != NULL)
369 fputs(" Mailx-Command", fp);
370 if(hp->h_mailx_raw_to != NULL) fputs(" Mailx-Raw-To", fp);
371 if(hp->h_mailx_raw_cc != NULL) fputs(" Mailx-Raw-Cc", fp);
372 if(hp->h_mailx_raw_bcc != NULL)
373 fputs(" Mailx-Raw-Bcc", fp);
374 if(hp->h_mailx_orig_from != NULL)
375 fputs(" Mailx-Orig-From", fp);
376 if(hp->h_mailx_orig_to != NULL)
377 fputs(" Mailx-Orig-To", fp);
378 if(hp->h_mailx_orig_cc != NULL)
379 fputs(" Mailx-Orig-Cc", fp);
380 if(hp->h_mailx_orig_bcc != NULL)
381 fputs(" Mailx-Orig-Bcc", fp);
383 /* Print only one instance of each free-form header */
384 for(hfp = hp->h_user_headers; hfp != NULL; hfp = hfp->hf_next){
385 struct n_header_field *hfpx;
387 for(hfpx = hp->h_user_headers;; hfpx = hfpx->hf_next)
388 if(hfpx == hfp){
389 putc(' ', fp);
390 fputs(&hfp->hf_dat[0], fp);
391 break;
392 }else if(!asccasecmp(&hfpx->hf_dat[0], &hfp->hf_dat[0]))
393 break;
395 if(putc('\n', fp) == EOF)
396 cp = NULL;
397 goto jleave;
400 if(cmda[2] != NULL)
401 goto jecmd;
403 if(!asccasecmp(cmda[1], cp = "Subject")){
404 np = (hp->h_subject != NULL) ? (struct name*)-1 : NULL;
405 goto jlist;
407 if(!asccasecmp(cmda[1], cp = "From")){
408 np = hp->h_from;
409 jlist:
410 fprintf(fp, "%s %s\n", (np == NULL ? "501" : "210"), cp);
411 goto jleave;
413 if(!asccasecmp(cmda[1], cp = "Sender")){
414 np = hp->h_sender;
415 goto jlist;
417 if(!asccasecmp(cmda[1], cp = "To")){
418 np = hp->h_to;
419 goto jlist;
421 if(!asccasecmp(cmda[1], cp = "Cc")){
422 np = hp->h_cc;
423 goto jlist;
425 if(!asccasecmp(cmda[1], cp = "Bcc")){
426 np = hp->h_bcc;
427 goto jlist;
429 if(!asccasecmp(cmda[1], cp = "Fcc")){
430 np = hp->h_fcc;
431 goto jlist;
433 if(!asccasecmp(cmda[1], cp = "Reply-To")){
434 np = hp->h_reply_to;
435 goto jlist;
437 if(!asccasecmp(cmda[1], cp = "Mail-Followup-To")){
438 np = hp->h_mft;
439 goto jlist;
441 if(!asccasecmp(cmda[1], cp = "Message-ID")){
442 np = hp->h_message_id;
443 goto jlist;
445 if(!asccasecmp(cmda[1], cp = "References")){
446 np = hp->h_ref;
447 goto jlist;
449 if(!asccasecmp(cmda[1], cp = "In-Reply-To")){
450 np = hp->h_in_reply_to;
451 goto jlist;
454 if(!asccasecmp(cmda[1], cp = "Mailx-Command")){
455 np = (hp->h_mailx_command != NULL) ? (struct name*)-1 : NULL;
456 goto jlist;
458 if(!asccasecmp(cmda[1], cp = "Mailx-Raw-To")){
459 np = hp->h_mailx_raw_to;
460 goto jlist;
462 if(!asccasecmp(cmda[1], cp = "Mailx-Raw-Cc")){
463 np = hp->h_mailx_raw_cc;
464 goto jlist;
466 if(!asccasecmp(cmda[1], cp = "Mailx-Raw-Bcc")){
467 np = hp->h_mailx_raw_bcc;
468 goto jlist;
470 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-From")){
471 np = hp->h_mailx_orig_from;
472 goto jlist;
474 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-To")){
475 np = hp->h_mailx_orig_to;
476 goto jlist;
478 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-Cc")){
479 np = hp->h_mailx_orig_cc;
480 goto jlist;
482 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-Bcc")){
483 np = hp->h_mailx_orig_bcc;
484 goto jlist;
487 /* Free-form header fields */
488 for(cp = cmda[1]; *cp != '\0'; ++cp)
489 if(!fieldnamechar(*cp)){
490 cp = cmda[1];
491 goto j501cp;
493 cp = cmda[1];
494 for(hfp = hp->h_user_headers;; hfp = hfp->hf_next){
495 if(hfp == NULL)
496 goto j501cp;
497 else if(!asccasecmp(cp, &hfp->hf_dat[0])){
498 if(fprintf(fp, "210 %s\n", &hfp->hf_dat[0]) < 0)
499 cp = NULL;
500 break;
503 }else if(is_asccaseprefix(cp, "remove")){
504 if(cmda[1] == NULL || cmda[2] != NULL)
505 goto jecmd;
506 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
507 goto j505r;
509 if(!asccasecmp(cmda[1], cp = "Subject")){
510 if(hp->h_subject != NULL){
511 hp->h_subject = NULL;
512 if(fprintf(fp, "210 %s\n", cp) < 0)
513 cp = NULL;
514 goto jleave;
515 }else
516 goto j501cp;
519 if(!asccasecmp(cmda[1], cp = "From")){
520 npp = &hp->h_from;
521 jrem:
522 if(*npp != NULL){
523 *npp = NULL;
524 if(fprintf(fp, "210 %s\n", cp) < 0)
525 cp = NULL;
526 goto jleave;
527 }else
528 goto j501cp;
530 if(!asccasecmp(cmda[1], cp = "Sender")){
531 npp = &hp->h_sender;
532 goto jrem;
534 if(!asccasecmp(cmda[1], cp = "To")){
535 npp = &hp->h_to;
536 goto jrem;
538 if(!asccasecmp(cmda[1], cp = "Cc")){
539 npp = &hp->h_cc;
540 goto jrem;
542 if(!asccasecmp(cmda[1], cp = "Bcc")){
543 npp = &hp->h_bcc;
544 goto jrem;
546 if(!asccasecmp(cmda[1], cp = "Fcc")){
547 npp = &hp->h_fcc;
548 goto jrem;
550 if(!asccasecmp(cmda[1], cp = "Reply-To")){
551 npp = &hp->h_reply_to;
552 goto jrem;
554 if(!asccasecmp(cmda[1], cp = "Mail-Followup-To")){
555 npp = &hp->h_mft;
556 goto jrem;
558 if(!asccasecmp(cmda[1], cp = "Message-ID")){
559 npp = &hp->h_message_id;
560 goto jrem;
562 if(!asccasecmp(cmda[1], cp = "References")){
563 npp = &hp->h_ref;
564 goto jrem;
566 if(!asccasecmp(cmda[1], cp = "In-Reply-To")){
567 npp = &hp->h_in_reply_to;
568 goto jrem;
571 if((cp = n_header_is_known(cmda[1], UIZ_MAX)) != NULL)
572 goto j505r;
574 /* Free-form header fields (note j501cp may print non-normalized name) */
575 /* C99 */{
576 struct n_header_field **hfpp;
577 bool_t any;
579 for(cp = cmda[1]; *cp != '\0'; ++cp)
580 if(!fieldnamechar(*cp)){
581 cp = cmda[1];
582 goto j501cp;
584 cp = cmda[1];
586 for(any = FAL0, hfpp = &hp->h_user_headers; (hfp = *hfpp) != NULL;){
587 if(!asccasecmp(cp, &hfp->hf_dat[0])){
588 *hfpp = hfp->hf_next;
589 if(!any){
590 if(fprintf(fp, "210 %s\n", &hfp->hf_dat[0]) < 0){
591 cp = NULL;
592 goto jleave;
595 any = TRU1;
596 }else
597 hfpp = &hfp->hf_next;
599 if(!any)
600 goto j501cp;
602 }else if(is_asccaseprefix(cp, "remove-at")){
603 if(cmda[1] == NULL || cmda[2] == NULL)
604 goto jecmd;
605 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
606 goto j505r;
608 if((n_idec_uiz_cp(&i, cmda[2], 0, NULL
609 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
610 ) != n_IDEC_STATE_CONSUMED || i == 0){
611 if(fprintf(fp, "505 invalid position: %s\n", cmda[2]) < 0)
612 cp = NULL;
613 goto jleave;
616 if(!asccasecmp(cmda[1], cp = "Subject")){
617 if(hp->h_subject != NULL && i == 1){
618 hp->h_subject = NULL;
619 if(fprintf(fp, "210 %s 1\n", cp) < 0)
620 cp = NULL;
621 goto jleave;
622 }else
623 goto j501cp;
626 if(!asccasecmp(cmda[1], cp = "From")){
627 npp = &hp->h_from;
628 jremat:
629 if((np = *npp) == NULL)
630 goto j501cp;
631 while(--i != 0 && np != NULL)
632 np = np->n_flink;
633 if(np == NULL)
634 goto j501cp;
636 if(np->n_blink != NULL)
637 np->n_blink->n_flink = np->n_flink;
638 else
639 *npp = np->n_flink;
640 if(np->n_flink != NULL)
641 np->n_flink->n_blink = np->n_blink;
643 if(fprintf(fp, "210 %s\n", cp) < 0)
644 cp = NULL;
645 goto jleave;
647 if(!asccasecmp(cmda[1], cp = "Sender")){
648 npp = &hp->h_sender;
649 goto jremat;
651 if(!asccasecmp(cmda[1], cp = "To")){
652 npp = &hp->h_to;
653 goto jremat;
655 if(!asccasecmp(cmda[1], cp = "Cc")){
656 npp = &hp->h_cc;
657 goto jremat;
659 if(!asccasecmp(cmda[1], cp = "Bcc")){
660 npp = &hp->h_bcc;
661 goto jremat;
663 if(!asccasecmp(cmda[1], cp = "Fcc")){
664 npp = &hp->h_fcc;
665 goto jremat;
667 if(!asccasecmp(cmda[1], cp = "Reply-To")){
668 npp = &hp->h_reply_to;
669 goto jremat;
671 if(!asccasecmp(cmda[1], cp = "Mail-Followup-To")){
672 npp = &hp->h_mft;
673 goto jremat;
675 if(!asccasecmp(cmda[1], cp = "Message-ID")){
676 npp = &hp->h_message_id;
677 goto jremat;
679 if(!asccasecmp(cmda[1], cp = "References")){
680 npp = &hp->h_ref;
681 goto jremat;
683 if(!asccasecmp(cmda[1], cp = "In-Reply-To")){
684 npp = &hp->h_in_reply_to;
685 goto jremat;
688 if((cp = n_header_is_known(cmda[1], UIZ_MAX)) != NULL)
689 goto j505r;
691 /* Free-form header fields */
692 /* C99 */{
693 struct n_header_field **hfpp;
695 for(cp = cmda[1]; *cp != '\0'; ++cp)
696 if(!fieldnamechar(*cp)){
697 cp = cmda[1];
698 goto j501cp;
700 cp = cmda[1];
702 for(hfpp = &hp->h_user_headers; (hfp = *hfpp) != NULL;){
703 if(--i == 0){
704 *hfpp = hfp->hf_next;
705 if(fprintf(fp, "210 %s %" PRIuZ "\n",
706 &hfp->hf_dat[0], i) < 0){
707 cp = NULL;
708 goto jleave;
710 break;
711 }else
712 hfpp = &hfp->hf_next;
714 if(hfp == NULL)
715 goto j501cp;
717 }else if(is_asccaseprefix(cp, "show")){
718 if(cmda[1] == NULL || cmda[2] != NULL)
719 goto jecmd;
721 if(!asccasecmp(cmda[1], cp = "Subject")){
722 if(hp->h_subject == NULL)
723 goto j501cp;
724 if(fprintf(fp, "212 %s\n%s\n\n", cp, hp->h_subject) < 0)
725 cp = NULL;
726 goto jleave;
729 if(!asccasecmp(cmda[1], cp = "From")){
730 np = hp->h_from;
731 jshow:
732 if(np != NULL){
733 fprintf(fp, "211 %s\n", cp);
734 do if(!(np->n_type & GDEL)){
735 switch(np->n_flags & NAME_ADDRSPEC_ISMASK){
736 case NAME_ADDRSPEC_ISFILE: cp = n_hy; break;
737 case NAME_ADDRSPEC_ISPIPE: cp = "|"; break;
738 case NAME_ADDRSPEC_ISNAME: cp = n_ns; break;
739 default: cp = np->n_name; break;
741 fprintf(fp, "%s %s\n", cp, np->n_fullname);
742 }while((np = np->n_flink) != NULL);
743 if(putc('\n', fp) == EOF)
744 cp = NULL;
745 goto jleave;
746 }else
747 goto j501cp;
749 if(!asccasecmp(cmda[1], cp = "Sender")){
750 np = hp->h_sender;
751 goto jshow;
753 if(!asccasecmp(cmda[1], cp = "To")){
754 np = hp->h_to;
755 goto jshow;
757 if(!asccasecmp(cmda[1], cp = "Cc")){
758 np = hp->h_cc;
759 goto jshow;
761 if(!asccasecmp(cmda[1], cp = "Bcc")){
762 np = hp->h_bcc;
763 goto jshow;
765 if(!asccasecmp(cmda[1], cp = "Fcc")){
766 np = hp->h_fcc;
767 goto jshow;
769 if(!asccasecmp(cmda[1], cp = "Reply-To")){
770 np = hp->h_reply_to;
771 goto jshow;
773 if(!asccasecmp(cmda[1], cp = "Mail-Followup-To")){
774 np = hp->h_mft;
775 goto jshow;
777 if(!asccasecmp(cmda[1], cp = "Message-ID")){
778 np = hp->h_message_id;
779 goto jshow;
781 if(!asccasecmp(cmda[1], cp = "References")){
782 np = hp->h_ref;
783 goto jshow;
785 if(!asccasecmp(cmda[1], cp = "In-Reply-To")){
786 np = hp->h_in_reply_to;
787 goto jshow;
790 if(!asccasecmp(cmda[1], cp = "Mailx-Command")){
791 if(hp->h_mailx_command == NULL)
792 goto j501cp;
793 if(fprintf(fp, "212 %s\n%s\n\n",
794 cp, hp->h_mailx_command) < 0)
795 cp = NULL;
796 goto jleave;
798 if(!asccasecmp(cmda[1], cp = "Mailx-Raw-To")){
799 np = hp->h_mailx_raw_to;
800 goto jshow;
802 if(!asccasecmp(cmda[1], cp = "Mailx-Raw-Cc")){
803 np = hp->h_mailx_raw_cc;
804 goto jshow;
806 if(!asccasecmp(cmda[1], cp = "Mailx-Raw-Bcc")){
807 np = hp->h_mailx_raw_bcc;
808 goto jshow;
810 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-From")){
811 np = hp->h_mailx_orig_from;
812 goto jshow;
814 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-To")){
815 np = hp->h_mailx_orig_to;
816 goto jshow;
818 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-Cc")){
819 np = hp->h_mailx_orig_cc;
820 goto jshow;
822 if(!asccasecmp(cmda[1], cp = "Mailx-Orig-Bcc")){
823 np = hp->h_mailx_orig_bcc;
824 goto jshow;
827 /* Free-form header fields */
828 /* C99 */{
829 bool_t any;
831 for(cp = cmda[1]; *cp != '\0'; ++cp)
832 if(!fieldnamechar(*cp)){
833 cp = cmda[1];
834 goto j501cp;
836 cp = cmda[1];
838 for(any = FAL0, hfp = hp->h_user_headers; hfp != NULL;
839 hfp = hfp->hf_next){
840 if(!asccasecmp(cp, &hfp->hf_dat[0])){
841 if(!any)
842 fprintf(fp, "212 %s\n", &hfp->hf_dat[0]);
843 any = TRU1;
844 fprintf(fp, "%s\n", &hfp->hf_dat[hfp->hf_nl +1]);
847 if(any){
848 if(putc('\n', fp) == EOF)
849 cp = NULL;
850 }else
851 goto j501cp;
853 }else
854 goto jecmd;
856 jleave:
857 NYD2_OU;
858 return (cp != NULL);
860 jecmd:
861 fputs("500\n", fp);
862 cp = NULL;
863 goto jleave;
864 j505r:
865 if(fprintf(fp, "505 read-only: %s\n", cp) < 0)
866 cp = NULL;
867 goto jleave;
868 j501cp:
869 if(fprintf(fp, "501 %s\n", cp) < 0)
870 cp = NULL;
871 goto jleave;
874 static bool_t
875 a_dmsg__attach(FILE *fp, struct n_dig_msg_ctx *dmcp, char const *cmda[3]){
876 bool_t status;
877 struct attachment *ap;
878 char const *cp;
879 struct header *hp;
880 NYD2_IN;
882 hp = dmcp->dmc_hp;
884 if((cp = cmda[0]) == NULL){
885 cp = n_empty; /* xxx not NULL anyway */
886 goto jdefault;
889 if(is_asccaseprefix(cp, "attribute")){
890 if(cmda[1] == NULL || cmda[2] != NULL)
891 goto jecmd;
893 if((ap = n_attachment_find(hp->h_attach, cmda[1], NULL)) != NULL){
894 jatt_att:
895 fprintf(fp, "212 %s\n", cmda[1]);
896 if(ap->a_msgno > 0){
897 if(fprintf(fp, "message-number %d\n\n", ap->a_msgno) < 0)
898 cp = NULL;
899 }else{
900 fprintf(fp,
901 "creation-name %s\nopen-path %s\nfilename %s\n",
902 ap->a_path_user, ap->a_path, ap->a_name);
903 if(ap->a_content_description != NULL)
904 fprintf(fp, "content-description %s\n",
905 ap->a_content_description);
906 if(ap->a_content_id != NULL)
907 fprintf(fp, "content-id %s\n",
908 ap->a_content_id->n_name);
909 if(ap->a_content_type != NULL)
910 fprintf(fp, "content-type %s\n", ap->a_content_type);
911 if(ap->a_content_disposition != NULL)
912 fprintf(fp, "content-disposition %s\n",
913 ap->a_content_disposition);
914 if(putc('\n', fp) == EOF)
915 cp = NULL;
917 }else{
918 if(fputs("501\n", fp) == EOF)
919 cp = NULL;
921 }else if(is_asccaseprefix(cp, "attribute-at")){
922 uiz_t i;
924 if(cmda[1] == NULL || cmda[2] != NULL)
925 goto jecmd;
927 if((n_idec_uiz_cp(&i, cmda[1], 0, NULL
928 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
929 ) != n_IDEC_STATE_CONSUMED || i == 0){
930 if(fprintf(fp, "505 invalid position: %s\n", cmda[1]) < 0)
931 cp = NULL;
932 }else{
933 for(ap = hp->h_attach; ap != NULL && --i != 0; ap = ap->a_flink)
935 if(ap != NULL)
936 goto jatt_att;
937 else{
938 if(fputs("501\n", fp) == EOF)
939 cp = NULL;
942 }else if(is_asccaseprefix(cp, "attribute-set")){
943 if(cmda[1] == NULL || cmda[2] == NULL)
944 goto jecmd;
945 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
946 goto j505r;
948 if((ap = n_attachment_find(hp->h_attach, cmda[1], NULL)) != NULL){
949 jatt_attset:
950 if(ap->a_msgno > 0){
951 if(fprintf(fp, "505 RFC822 message attachment: %s\n",
952 cmda[1]) < 0)
953 cp = NULL;
954 }else{
955 char c, *keyw;
957 cp = cmda[2];
958 while((c = *cp) != '\0' && !blankchar(c))
959 ++cp;
960 keyw = savestrbuf(cmda[2], PTR2SIZE(cp - cmda[2]));
961 if(c != '\0'){
962 for(; (c = *++cp) != '\0' && blankchar(c);)
964 if(c != '\0'){
965 char *xp;
967 /* Strip [\r\n] which would render a parameter invalid XXX
968 * XXX all controls? */
969 cp = xp = savestr(cp);
970 for(; (c = *xp) != '\0'; ++xp)
971 if(c == '\n' || c == '\r')
972 *xp = ' ';
973 c = *cp;
977 if(!asccasecmp(keyw, "filename"))
978 ap->a_name = (c == '\0') ? ap->a_path_bname : cp;
979 else if(!asccasecmp(keyw, "content-description"))
980 ap->a_content_description = (c == '\0') ? NULL : cp;
981 else if(!asccasecmp(keyw, "content-id")){
982 ap->a_content_id = NULL;
984 if(c != '\0'){
985 struct name *np;
987 np = checkaddrs(lextract(cp, GREF),
988 /*EACM_STRICT | TODO '/' valid!! */ EACM_NOLOG |
989 EACM_NONAME, NULL);
990 if(np != NULL && np->n_flink == NULL)
991 ap->a_content_id = np;
992 else
993 cp = NULL;
995 }else if(!asccasecmp(keyw, "content-type"))
996 ap->a_content_type = (c == '\0') ? NULL : cp;
997 else if(!asccasecmp(keyw, "content-disposition"))
998 ap->a_content_disposition = (c == '\0') ? NULL : cp;
999 else
1000 cp = NULL;
1002 if(cp != NULL){
1003 size_t i;
1005 for(i = 0; ap != NULL; ++i, ap = ap->a_blink)
1007 if(fprintf(fp, "210 %" PRIuZ "\n", i) < 0)
1008 cp = NULL;
1009 }else{
1010 if(fputs("505\n", fp) == EOF)
1011 cp = NULL;
1014 }else{
1015 if(fputs("501\n", fp) == EOF)
1016 cp = NULL;
1018 }else if(is_asccaseprefix(cp, "attribute-set-at")){
1019 uiz_t i;
1021 if(cmda[1] == NULL || cmda[2] == NULL)
1022 goto jecmd;
1023 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
1024 goto j505r;
1026 if((n_idec_uiz_cp(&i, cmda[1], 0, NULL
1027 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
1028 ) != n_IDEC_STATE_CONSUMED || i == 0){
1029 if(fprintf(fp, "505 invalid position: %s\n", cmda[1]) < 0)
1030 cp = NULL;
1031 }else{
1032 for(ap = hp->h_attach; ap != NULL && --i != 0; ap = ap->a_flink)
1034 if(ap != NULL)
1035 goto jatt_attset;
1036 else{
1037 if(fputs("501\n", fp) == EOF)
1038 cp = NULL;
1041 }else if(is_asccaseprefix(cmda[0], "insert")){
1042 enum n_attach_error aerr;
1044 if(cmda[1] == NULL || cmda[2] != NULL)
1045 goto jecmd;
1046 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
1047 goto j505r;
1049 hp->h_attach = n_attachment_append(hp->h_attach, cmda[1], &aerr, &ap);
1050 switch(aerr){
1051 case n_ATTACH_ERR_FILE_OPEN: cp = "505\n"; goto jatt_ins;
1052 case n_ATTACH_ERR_ICONV_FAILED: cp = "506\n"; goto jatt_ins;
1053 case n_ATTACH_ERR_ICONV_NAVAIL:
1054 case n_ATTACH_ERR_OTHER:
1055 default:
1056 cp = "501\n";
1057 jatt_ins:
1058 if(fprintf(fp, "%s %s\n", cp, cmda[1]) < 0)
1059 cp = NULL;
1060 break;
1061 case n_ATTACH_ERR_NONE:{
1062 size_t i;
1064 for(i = 0; ap != NULL; ++i, ap = ap->a_blink)
1066 if(fprintf(fp, "210 %" PRIuZ "\n", i) < 0)
1067 cp = NULL;
1068 }break;
1070 goto jleave;
1071 }else if(is_asccaseprefix(cp, "list")){
1072 jdefault:
1073 if(cmda[1] != NULL)
1074 goto jecmd;
1076 if((ap = hp->h_attach) != NULL){
1077 fputs("212\n", fp);
1079 fprintf(fp, "%s\n", ap->a_path_user);
1080 while((ap = ap->a_flink) != NULL);
1081 if(putc('\n', fp) == EOF)
1082 cp = NULL;
1083 }else{
1084 if(fputs("501\n", fp) == EOF)
1085 cp = NULL;
1087 }else if(is_asccaseprefix(cmda[0], "remove")){
1088 if(cmda[1] == NULL || cmda[2] != NULL)
1089 goto jecmd;
1090 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
1091 goto j505r;
1093 if((ap = n_attachment_find(hp->h_attach, cmda[1], &status)) != NULL){
1094 if(status == TRUM1){
1095 if(fputs("506\n", fp) == EOF)
1096 cp = NULL;
1097 }else{
1098 hp->h_attach = n_attachment_remove(hp->h_attach, ap);
1099 if(fprintf(fp, "210 %s\n", cmda[1]) < 0)
1100 cp = NULL;
1102 }else{
1103 if(fputs("501\n", fp) == EOF)
1104 cp = NULL;
1106 }else if(is_asccaseprefix(cp, "remove-at")){
1107 uiz_t i;
1109 if(cmda[1] == NULL || cmda[2] != NULL)
1110 goto jecmd;
1111 if(dmcp->dmc_flags & n_DIG_MSG_RDONLY)
1112 goto j505r;
1114 if((n_idec_uiz_cp(&i, cmda[1], 0, NULL
1115 ) & (n_IDEC_STATE_EMASK | n_IDEC_STATE_CONSUMED)
1116 ) != n_IDEC_STATE_CONSUMED || i == 0){
1117 if(fprintf(fp, "505 invalid position: %s\n", cmda[1]) < 0)
1118 cp = NULL;
1119 }else{
1120 for(ap = hp->h_attach; ap != NULL && --i != 0; ap = ap->a_flink)
1122 if(ap != NULL){
1123 hp->h_attach = n_attachment_remove(hp->h_attach, ap);
1124 if(fprintf(fp, "210 %s\n", cmda[1]) < 0)
1125 cp = NULL;
1126 }else{
1127 if(fputs("501\n", fp) == EOF)
1128 cp = NULL;
1131 }else
1132 goto jecmd;
1134 jleave:
1135 NYD2_OU;
1136 return (cp != NULL);
1137 jecmd:
1138 (void)fputs("500\n", fp);
1139 cp = NULL;
1140 goto jleave;
1141 j505r:
1142 if(fprintf(fp, "505 read-only: %s\n", cp) < 0)
1143 cp = NULL;
1144 goto jleave;
1147 FL void
1148 n_dig_msg_on_mailbox_close(struct mailbox *mbp){
1149 struct n_dig_msg_ctx *dmcp;
1150 NYD_IN;
1152 while((dmcp = mbp->mb_digmsg) != NULL){
1153 mbp->mb_digmsg = dmcp->dmc_next;
1154 if(dmcp->dmc_flags & n_DIG_MSG_FCLOSE)
1155 fclose(dmcp->dmc_fp);
1156 if(dmcp->dmc_flags & n_DIG_MSG_OWN_MEMPOOL){
1157 n_memory_pool_push(dmcp->dmc_mempool, FAL0);
1158 n_memory_pool_pop(dmcp->dmc_mempool, TRU1);
1160 n_free(dmcp);
1162 NYD_OU;
1165 FL bool_t
1166 n_dig_msg_circumflex(struct n_dig_msg_ctx *dmcp, FILE *fp, char const *cmd){
1167 bool_t rv;
1168 char const *cp, *cmd_top;
1169 NYD_IN;
1171 cp = cmd;
1172 while(blankchar(*cp))
1173 ++cp;
1174 cmd = cp;
1175 for(cmd_top = cp; *cp != '\0'; cmd_top = cp++)
1176 if(blankchar(*cp))
1177 break;
1179 rv = a_dmsg_cmd(fp, dmcp, cmd, PTR2SIZE(cmd_top - cmd), cp);
1180 NYD_OU;
1181 return rv;
1184 FL int
1185 c_digmsg(void *vp){
1186 char const *cp, *emsg;
1187 struct n_dig_msg_ctx *dmcp;
1188 struct n_cmd_arg *cap;
1189 struct n_cmd_arg_ctx *cacp;
1190 NYD_IN;
1192 n_pstate_err_no = n_ERR_NONE;
1193 cacp = vp;
1194 cap = cacp->cac_arg;
1196 if(is_asccaseprefix(cp = cap->ca_arg.ca_str.s, "create")){
1197 if(cacp->cac_no < 2 || cacp->cac_no > 3)
1198 goto jesynopsis;
1199 cap = cap->ca_next;
1201 /* Request to use STDOUT? */
1202 if(cacp->cac_no == 3){
1203 cp = cap->ca_next->ca_arg.ca_str.s;
1204 if(*cp != '-' || cp[1] != '\0'){
1205 emsg = N_("`digmsg': create: invalid I/O channel: %s\n");
1206 goto jeinval_quote;
1210 /* First of all, our context object */
1211 switch(a_dmsg_find(cp = cap->ca_arg.ca_str.s, &dmcp, TRU1)){
1212 case n_ERR_INVAL:
1213 emsg = N_("`digmsg': create: message number invalid: %s\n");
1214 goto jeinval_quote;
1215 case n_ERR_EXIST:
1216 emsg = N_("`digmsg': create: message object already exists: %s\n");
1217 goto jeinval_quote;
1218 default:
1219 break;
1222 if(dmcp->dmc_flags & n_DIG_MSG_COMPOSE)
1223 dmcp->dmc_flags = n_DIG_MSG_COMPOSE | n_DIG_MSG_COMPOSE_DIGGED;
1224 else{
1225 FILE *fp;
1227 if((fp = setinput(&mb, dmcp->dmc_mp, NEED_HEADER)) == NULL){
1228 /* XXX Should have paniced before.. */
1229 n_free(dmcp);
1230 emsg = N_("`digmsg': create: mailbox I/O error for message: %s\n");
1231 goto jeinval_quote;
1234 n_memory_pool_push(dmcp->dmc_mempool, TRU1);
1235 /* XXX n_header_extract error!! */
1236 n_header_extract((n_HEADER_EXTRACT_FULL |
1237 n_HEADER_EXTRACT_PREFILL_RECEIVERS |
1238 n_HEADER_EXTRACT_IGNORE_FROM_), fp, dmcp->dmc_hp, NULL);
1239 n_memory_pool_pop(dmcp->dmc_mempool, FAL0);
1242 if(cacp->cac_no == 3)
1243 dmcp->dmc_fp = n_stdout;
1244 /* For compose mode simply use OF_REGISTER, the number of dangling
1245 * deleted files with open descriptors until next close_all_files()
1246 * should be very small; if this paradigm is changed
1247 * n_DIG_MSG_COMPOSE_GUT() needs to be adjusted */
1248 else if((dmcp->dmc_fp = Ftmp(NULL, "digmsg", (OF_RDWR | OF_UNLINK |
1249 (dmcp->dmc_flags & n_DIG_MSG_COMPOSE ? OF_REGISTER : 0)))
1250 ) != NULL)
1251 dmcp->dmc_flags |= n_DIG_MSG_HAVE_FP |
1252 (dmcp->dmc_flags & n_DIG_MSG_COMPOSE ? 0 : n_DIG_MSG_FCLOSE);
1253 else{
1254 n_err(_("`digmsg': create: cannot create temporary file: %s\n"),
1255 n_err_to_doc(n_pstate_err_no = n_err_no));
1256 vp = NULL;
1257 goto jeremove;
1260 if(!(dmcp->dmc_flags & n_DIG_MSG_COMPOSE)){
1261 dmcp->dmc_last = NULL;
1262 if((dmcp->dmc_next = mb.mb_digmsg) != NULL)
1263 dmcp->dmc_next->dmc_last = dmcp;
1264 mb.mb_digmsg = dmcp;
1266 }else if(is_asccaseprefix(cp, "remove")){
1267 if(cacp->cac_no != 2)
1268 goto jesynopsis;
1269 cap = cap->ca_next;
1271 switch(a_dmsg_find(cp = cap->ca_arg.ca_str.s, &dmcp, FAL0)){
1272 case n_ERR_INVAL:
1273 emsg = N_("`digmsg': remove: message number invalid: %s\n");
1274 goto jeinval_quote;
1275 default:
1276 if(!(dmcp->dmc_flags & n_DIG_MSG_COMPOSE) ||
1277 (dmcp->dmc_flags & n_DIG_MSG_COMPOSE_DIGGED))
1278 break;
1279 /* FALLTHRU */
1280 case n_ERR_NOENT:
1281 emsg = N_("`digmsg': remove: no such message object: %s\n");
1282 goto jeinval_quote;
1285 if(!(dmcp->dmc_flags & n_DIG_MSG_COMPOSE)){
1286 if(dmcp->dmc_last != NULL)
1287 dmcp->dmc_last->dmc_next = dmcp->dmc_next;
1288 else{
1289 assert(dmcp == mb.mb_digmsg);
1290 mb.mb_digmsg = dmcp->dmc_next;
1292 if(dmcp->dmc_next != NULL)
1293 dmcp->dmc_next->dmc_last = dmcp->dmc_last;
1296 if(dmcp->dmc_flags & n_DIG_MSG_FCLOSE)
1297 fclose(dmcp->dmc_fp);
1298 jeremove:
1299 if(dmcp->dmc_flags & n_DIG_MSG_OWN_MEMPOOL){
1300 n_memory_pool_push(dmcp->dmc_mempool, FAL0);
1301 n_memory_pool_pop(dmcp->dmc_mempool, TRU1);
1304 if(dmcp->dmc_flags & n_DIG_MSG_COMPOSE)
1305 dmcp->dmc_flags = n_DIG_MSG_COMPOSE;
1306 else
1307 n_free(dmcp);
1308 }else{
1309 switch(a_dmsg_find(cp, &dmcp, FAL0)){
1310 case n_ERR_INVAL:
1311 emsg = N_("`digmsg': message number invalid: %s\n");
1312 goto jeinval_quote;
1313 case n_ERR_NOENT:
1314 emsg = N_("`digmsg': no such message object: %s\n");
1315 goto jeinval_quote;
1316 default:
1317 break;
1319 cap = cap->ca_next;
1321 if(dmcp->dmc_flags & n_DIG_MSG_HAVE_FP){
1322 rewind(dmcp->dmc_fp);
1323 ftruncate(fileno(dmcp->dmc_fp), 0);
1326 n_memory_pool_push(dmcp->dmc_mempool, FAL0);
1327 /* C99 */{
1328 struct str cmds_b, *cmdsp;
1330 cp = n_empty;
1331 if(cap == NULL){ /* XXX cmd_arg_parse is stupid */
1332 cmdsp = &cmds_b;
1333 cmdsp->s = n_UNCONST(cp);
1334 cmdsp->l = 0;
1335 }else{
1336 cmdsp = &cap->ca_arg.ca_str;
1337 if((cap = cap->ca_next) != NULL)
1338 cp = cap->ca_arg.ca_str.s;
1340 if(!a_dmsg_cmd(dmcp->dmc_fp, dmcp, cmdsp->s, cmdsp->l, cp))
1341 vp = NULL;
1343 n_memory_pool_pop(dmcp->dmc_mempool, FAL0);
1345 if(dmcp->dmc_flags & n_DIG_MSG_HAVE_FP){
1346 rewind(dmcp->dmc_fp);
1347 n_digmsg_read_overlay = dmcp;
1351 jleave:
1352 NYD_OU;
1353 return (vp == NULL);
1355 jesynopsis:
1356 n_err(_("Synopsis: digmsg: <command> <-|msgno> [<:argument:>]\n"));
1357 goto jeinval;
1358 jeinval_quote:
1359 n_err(V_(emsg), n_shexp_quote_cp(cp, FAL0));
1360 jeinval:
1361 n_pstate_err_no = n_ERR_INVAL;
1362 vp = NULL;
1363 goto jleave;
1366 /* s-it-mode */