Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/mailx/cmd2.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the BSD package *
4
*Copyright (c) 1978-2011 The Regents of the University of California an*
5
* *
6
* Redistribution and use in source and binary forms, with or *
7
* without modification, are permitted provided that the following *
8
* conditions are met: *
9
* *
10
* 1. Redistributions of source code must retain the above *
11
* copyright notice, this list of conditions and the *
12
* following disclaimer. *
13
* *
14
* 2. Redistributions in binary form must reproduce the above *
15
* copyright notice, this list of conditions and the *
16
* following disclaimer in the documentation and/or other *
17
* materials provided with the distribution. *
18
* *
19
* 3. Neither the name of The Regents of the University of California*
20
* names of its contributors may be used to endorse or *
21
* promote products derived from this software without *
22
* specific prior written permission. *
23
* *
24
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
25
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
26
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
27
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
28
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS *
29
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
30
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED *
31
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
32
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *
33
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *
34
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
35
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
36
* POSSIBILITY OF SUCH DAMAGE. *
37
* *
38
* Redistribution and use in source and binary forms, with or without *
39
* modification, are permitted provided that the following conditions *
40
* are met: *
41
* 1. Redistributions of source code must retain the above copyright *
42
* notice, this list of conditions and the following disclaimer. *
43
* 2. Redistributions in binary form must reproduce the above copyright *
44
* notice, this list of conditions and the following disclaimer in *
45
* the documentation and/or other materials provided with the *
46
* distribution. *
47
* 3. Neither the name of the University nor the names of its *
48
* contributors may be used to endorse or promote products derived *
49
* from this software without specific prior written permission. *
50
* *
51
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" *
52
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
53
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
54
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS *
55
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
56
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
57
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *
58
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
59
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *
60
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *
61
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
62
* SUCH DAMAGE. *
63
* *
64
* Kurt Shoens (UCB) *
65
* gsf *
66
* *
67
***********************************************************************/
68
#pragma prototyped
69
/*
70
* Mail -- a mail program
71
*
72
* More user commands.
73
*/
74
75
#include "mailx.h"
76
77
/*
78
* If any arguments were given, go to the next applicable argument
79
* following dot, otherwise, go to the next applicable message.
80
* If given as first command with no arguments, print first message.
81
*/
82
int
83
next(struct msg* msgvec)
84
{
85
register struct msg* mp;
86
register struct msg* ip;
87
register struct msg* ip2;
88
register int skip;
89
int mdot;
90
91
skip = MDELETE|MNONE;
92
if (msgvec->m_index) {
93
/*
94
* If some messages were supplied, find the
95
* first applicable one following dot using
96
* wrap around.
97
*/
98
99
mdot = state.msg.dot - state.msg.list + 1;
100
101
/*
102
* Find the first message in the supplied
103
* message list which follows dot.
104
*/
105
106
for (ip = msgvec;; ip++)
107
if (!ip->m_index) {
108
ip = msgvec;
109
break;
110
}
111
else if (ip->m_index > mdot)
112
break;
113
ip2 = ip;
114
do {
115
mp = state.msg.list + ip2->m_index - 1;
116
if (!(mp->m_flag & skip)) {
117
state.msg.dot = mp;
118
goto hitit;
119
}
120
if (ip2->m_index)
121
ip2++;
122
if (!ip2->m_index)
123
ip2 = msgvec;
124
} while (ip2 != ip);
125
note(0, "No messages applicable");
126
return 1;
127
}
128
129
/*
130
* If this is the first command, select message 1.
131
* Note that this must exist for us to get here at all.
132
*/
133
134
if (!state.sawcom)
135
goto hitit;
136
137
/*
138
* Just find the next good message after dot, no
139
* wraparound.
140
*/
141
142
skip |= MSAVE;
143
if (!state.edit && state.var.spamlog)
144
skip |= MSPAM;
145
for (mp = state.msg.dot + 1; mp < state.msg.list + state.msg.count; mp++)
146
if (!(mp->m_flag & skip))
147
break;
148
if (mp >= state.msg.list + state.msg.count) {
149
note(0, "At EOF");
150
return 0;
151
}
152
state.msg.dot = mp;
153
hitit:
154
/*
155
* Print dot.
156
*/
157
158
state.msg.list->m_index = state.msg.dot - state.msg.list + 1;
159
(state.msg.list + 1)->m_index = 0;
160
return type(state.msg.list);
161
}
162
163
/*
164
* Snarf the file from the end of the command line and
165
* return a pointer to it. If there is no file attached,
166
* just return 0. Put a null in front of the file
167
* name so that the message list processing won't see it,
168
* If the file name is the only thing on the line return 0
169
* in the reference flag variable.
170
*/
171
172
char*
173
snarf(char* line, int* flag)
174
{
175
register char* s;
176
register int quote;
177
178
if (!*line) {
179
*flag = 0;
180
return 0;
181
}
182
s = line + strlen(line) - 1;
183
184
/*
185
* Strip away trailing blanks.
186
*/
187
188
while (s > line && isspace(*s))
189
s--;
190
*++s = 0;
191
192
/*
193
* cmdpipe() allows quoted string as last arg.
194
*/
195
196
if (s > line && (*(s - 1) == '"' || *(s - 1) == '\'')) {
197
quote = *--s;
198
*s = 0;
199
do {
200
if (s <= line) {
201
note(0, "Unbalanced %c quote", quote);
202
*flag = -1;
203
return 0;
204
}
205
} while (*--s != quote);
206
*flag = s > line;
207
*s++ = 0;
208
return s;
209
}
210
211
/*
212
* Now search for the beginning of the file name.
213
*/
214
215
while (s > line && !isspace(*s))
216
s--;
217
if (!*s) {
218
*flag = 0;
219
return 0;
220
}
221
if (isspace(*s)) {
222
*s++ = 0;
223
*flag = 1;
224
}
225
else
226
*flag = 0;
227
return s;
228
}
229
230
/*
231
* Save/copy the indicated messages at the end of the passed file name.
232
* If mark is true, mark the message "saved."
233
*/
234
static int
235
save1(char* str, Dt_t** ignore, unsigned long flags)
236
{
237
register struct msg* ip;
238
register struct msg* mp;
239
char* file;
240
char* disp;
241
char* temp;
242
int f;
243
FILE* fp;
244
int folder;
245
struct mhcontext mh;
246
struct stat st;
247
248
if (!(file = snarf(str, &f))) {
249
if (f < 0)
250
return 1;
251
}
252
else if (streq(file, "+")) {
253
file = 0;
254
flags |= FOLLOWUP;
255
}
256
if (!f) {
257
if (!(state.msg.list->m_index = first(0, MMNORM))) {
258
note(0, "No messages to %s", state.cmd->c_name);
259
return 1;
260
}
261
(state.msg.list + 1)->m_index = 0;
262
}
263
else if (getmsglist(str, 0) < 0)
264
return 1;
265
if (flags & FOLLOWUP)
266
file = record(file ? file : grab(state.msg.list + state.msg.list->m_index - 1, GREPLY, NiL), flags);
267
else file = expand(file ? file : "&", 1);
268
if (!file)
269
return 1;
270
if (state.var.debug) {
271
note(DEBUG, "%s to \"%s\"", state.cmd->c_name, file);
272
return 0;
273
}
274
note(PROMPT, "\"%s\" ", file);
275
folder = FFILE;
276
if (stat(file, &st) < 0) {
277
if (*file == '@') {
278
folder = FIMAP;
279
disp = "[Imap]";
280
}
281
else
282
disp = "[New file]";
283
}
284
else if (S_ISDIR(st.st_mode)) {
285
folder = FMH;
286
disp = "[Added]";
287
}
288
else if (S_ISREG(st.st_mode))
289
disp = state.clobber ? "[Overwritten]" : "[Appended]";
290
else {
291
note(0, "%s: cannot save to file", file);
292
return 1;
293
}
294
switch (folder) {
295
case FFILE:
296
if (!(fp = fileopen(file, state.clobber ? "EMw" : "EMa")))
297
return 1;
298
for (ip = state.msg.list; ip->m_index; ip++) {
299
mp = state.msg.list + ip->m_index - 1;
300
touchmsg(mp);
301
if (copy(mp, fp, ignore, NiL, 0) < 0) {
302
note(SYSTEM, "%s", file);
303
fileclose(fp);
304
return 1;
305
}
306
if (flags & MARK)
307
msgflags(mp, MSAVE, 0);
308
}
309
if (fileclose(fp))
310
note(SYSTEM, "%s", file);
311
break;
312
case FIMAP:
313
for (ip = state.msg.list; ip->m_index; ip++) {
314
mp = state.msg.list + ip->m_index - 1;
315
touchmsg(mp);
316
if (imap_save(mp, file) < 0) {
317
note(SYSTEM, "%s", file);
318
return 1;
319
}
320
if (flags & MARK)
321
msgflags(mp, MSAVE, 0);
322
}
323
break;
324
case FMH:
325
mhgetcontext(&mh, file, 1);
326
for (ip = state.msg.list; ip->m_index; ip++) {
327
mp = state.msg.list + ip->m_index - 1;
328
touchmsg(mp);
329
sfprintf(state.path.temp, "%s/%d", file, mh.next);
330
temp = struse(state.path.temp);
331
if (fp = fileopen(temp, "MEw")) {
332
if (copy(mp, fp, ignore, NiL, 0) < 0)
333
note(SYSTEM, "%s", temp);
334
fileclose(fp);
335
if (flags & MARK)
336
msgflags(mp, MSAVE, 0);
337
mh.next++;
338
}
339
}
340
mhputcontext(&mh, file);
341
break;
342
}
343
note(0, "%s", disp);
344
return 0;
345
}
346
347
/*
348
* Save a message in a file. Mark the message as saved
349
* so we can discard when the user quits.
350
*/
351
int
352
save(char* str)
353
{
354
return save1(str, &state.saveignore, MARK);
355
}
356
357
/*
358
* Save a message in a FOLLOWUP file. Mark the message as saved
359
* so we can discard when the user quits.
360
*/
361
int
362
Save(char* str)
363
{
364
return save1(str, &state.saveignore, FOLLOWUP|MARK);
365
}
366
367
/*
368
* Copy a message to a file without affected its saved-ness
369
*/
370
int
371
cmdcopy(char* str)
372
{
373
return save1(str, &state.saveignore, 0);
374
}
375
376
/*
377
* Copy a message to a FOLLOWUP file without affected its saved-ness
378
*/
379
int
380
Copy(char* str)
381
{
382
return save1(str, &state.saveignore, FOLLOWUP);
383
}
384
385
/*
386
* Write the indicated messages at the end of the passed
387
* file name, minus header and trailing blank line.
388
*/
389
int
390
cmdwrite(char* str)
391
{
392
return save1(str, &state.ignoreall, MARK);
393
}
394
395
/*
396
* Delete the indicated messages.
397
* Set dot to some nice place afterwards.
398
* Internal interface.
399
*/
400
static int
401
delm(struct msg* msgvec)
402
{
403
register struct msg* mp;
404
register struct msg* ip;
405
int last;
406
407
last = 0;
408
for (ip = msgvec; ip->m_index; ip++) {
409
mp = state.msg.list + ip->m_index - 1;
410
touchmsg(mp);
411
msgflags(mp, MDELETE|MTOUCH, MPRESERVE|MSAVE|MBOX);
412
last = ip->m_index;
413
}
414
if (last) {
415
state.msg.dot = state.msg.list + last - 1;
416
last = first(0, MDELETE);
417
if (last) {
418
state.msg.dot = state.msg.list + last - 1;
419
return 0;
420
}
421
else {
422
state.msg.dot = state.msg.list;
423
return -1;
424
}
425
}
426
427
/*
428
* Following can't happen -- it keeps lint happy
429
*/
430
431
return -1;
432
}
433
434
/*
435
* Delete messages.
436
*/
437
int
438
cmddelete(struct msg* msgvec)
439
{
440
delm(msgvec);
441
return 0;
442
}
443
444
/*
445
* Delete messages, then type the new dot.
446
*/
447
int
448
deltype(struct msg* msgvec)
449
{
450
int lastdot;
451
452
lastdot = state.msg.dot - state.msg.list + 1;
453
if (delm(msgvec) >= 0) {
454
if ((state.msg.list->m_index = state.msg.dot - state.msg.list + 1) > lastdot) {
455
touchmsg(state.msg.dot);
456
(state.msg.list + 1)->m_index = 0;
457
return type(state.msg.list);
458
}
459
note(0, "At EOF");
460
}
461
else
462
note(0, "No more messages");
463
return 0;
464
}
465
466
/*
467
* Undelete the indicated messages.
468
*/
469
int
470
undelete(struct msg* msgvec)
471
{
472
register struct msg* mp;
473
register struct msg* ip;
474
475
for (ip = msgvec; ip->m_index; ip++) {
476
mp = state.msg.list + ip->m_index - 1;
477
touchmsg(mp);
478
state.msg.dot = mp;
479
msgflags(mp, 0, MDELETE);
480
}
481
return 0;
482
}
483
484
/*
485
* Print out all currently retained fields.
486
*/
487
static int
488
ignoreshow(Dt_t* dt, void* object, void* context)
489
{
490
if (((struct name*)object)->flags & *((int*)context)) {
491
*((int*)context) |= HIT;
492
printf("%s\n", ((struct name*)object)->name);
493
}
494
return 0;
495
}
496
497
/*
498
* Low level for ignore and retain.
499
*/
500
501
static int
502
ignore1(Dt_t** ignore, char** list, unsigned long flags)
503
{
504
register char** ap;
505
register struct name* tp;
506
507
if (*list) {
508
for (ap = list; *ap; ap++)
509
if (tp = dictsearch(ignore, *ap, INSERT|IGNORECASE))
510
tp->flags = flags;
511
if (*ignore)
512
dictflags(ignore) |= flags;
513
}
514
else {
515
dictwalk(ignore, ignoreshow, &flags);
516
if (!(flags & HIT))
517
note(0, "No fields currently being %s", (flags & RETAIN) ? "retained" : "ignored");
518
}
519
return 0;
520
}
521
522
/*
523
* Add the given header fields to the retained list.
524
* If no arguments, print the current list of retained fields.
525
*/
526
int
527
retain(char** list)
528
{
529
530
return ignore1(&state.ignore, list, RETAIN);
531
}
532
533
int
534
saveretain(char** list)
535
{
536
537
return ignore1(&state.saveignore, list, RETAIN);
538
}
539
540
/*
541
* Add the given header fields to the ignored list.
542
* If no arguments, print the current list of ignored fields.
543
*/
544
int
545
ignore(char** list)
546
{
547
return ignore1(&state.ignore, list, IGNORE);
548
}
549
550
int
551
saveignore(char** list)
552
{
553
return ignore1(&state.saveignore, list, IGNORE);
554
}
555
556
/*
557
* Send mail to a bunch of user names.
558
*/
559
int
560
mail(char* str)
561
{
562
struct header head;
563
564
memset(&head, 0, sizeof(head));
565
extract(&head, GTO|GMETOO, str);
566
sendmail(&head, 0);
567
return 0;
568
}
569
570
/*
571
* Low level for map().
572
*/
573
static int
574
maplist(Dt_t* dt, void* object, void* context)
575
{
576
printf("%s ", ((struct name*)object)->name);
577
return 0;
578
}
579
580
/*
581
* List mapped user names by expanding aliases.
582
*/
583
int
584
map(char* str)
585
{
586
struct header head;
587
588
memset(&head, 0, sizeof(head));
589
extract(&head, GTO|GMETOO, str);
590
usermap(&head, state.clobber);
591
dictwalk(&head.h_names, maplist, NiL);
592
printf("\n");
593
return 0;
594
}
595
596
/*
597
* Get an attachment from ap in the current message.
598
*/
599
static int
600
getatt(register struct part* ap, register char* name, unsigned long flags, off_t* lines, off_t* chars)
601
{
602
register char* s;
603
register int n;
604
char* cmd;
605
off_t lc;
606
off_t cc;
607
FILE* ip;
608
FILE* op;
609
struct stat st;
610
611
if (name == ap->name) {
612
cmd = 0;
613
if (state.var.attachments) {
614
sfprintf(state.path.temp, "%s/%s", state.var.attachments, name);
615
name = expand(struse(state.path.temp), 1);
616
}
617
else
618
name = savestr(name);
619
}
620
else if (!(cmd = iscmd(name)) && !(name = expand(name, 1)))
621
return 1;
622
if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
623
if (s = strrchr(ap->name, '/'))
624
s++;
625
else
626
s = ap->name;
627
if (!streq(name, ".")) {
628
sfprintf(state.path.temp, "%s/%s", name, s);
629
s = struse(state.path.temp);
630
}
631
name = savestr(s);
632
}
633
if (!ap->code[0] && mimeview(state.part.mime, "encoding", name, ap->type, ap->opts))
634
strncopy(ap->code, ap->type, sizeof(ap->code));
635
if (ap->code[0] && !isdigit(ap->code[0])) {
636
sfprintf(state.path.temp, "uudecode -h -x %s", ap->code);
637
if (!mimecmp("text", ap->type, NiL))
638
sfprintf(state.path.temp, " -t");
639
if (cmd)
640
sfprintf(state.path.temp, " -o - | %s", cmd);
641
else if (filestd(name, "w")) {
642
if ((flags & GMIME) && mime(1) && (s = mimeview(state.part.mime, NiL, NiL, ap->type, ap->opts)))
643
sfprintf(state.path.temp, " | %s", s);
644
sfprintf(state.path.temp, " | %s", state.var.pager);
645
}
646
else
647
{
648
sfprintf(state.path.temp, " -o ");
649
shquote(state.path.temp, name);
650
}
651
s = struse(state.path.temp);
652
n = 1;
653
}
654
else if (cmd) {
655
s = cmd;
656
n = -1;
657
}
658
else if (filestd(name, "w")) {
659
if ((flags & GMIME) && mime(1) && (s = mimeview(state.part.mime, NiL, NiL, ap->type, ap->opts))) {
660
sfprintf(state.path.temp, "%s | %s", s, state.var.pager);
661
s = struse(state.path.temp);
662
n = 1;
663
}
664
else {
665
s = state.var.pager;
666
n = -1;
667
}
668
}
669
else {
670
s = name;
671
n = 0;
672
}
673
if (!(op = n ? pipeopen(s, "w") : fileopen(s, "ERw")))
674
return 1;
675
ip = setinput(state.msg.dot);
676
fseek(ip, ap->offset, SEEK_SET);
677
if (!lines)
678
lines = &lc;
679
if (!chars)
680
chars = &cc;
681
filecopy(NiL, ip, name, op, NiL, ap->size, lines, chars, 0);
682
fileclose(op);
683
if (flags & GDISPLAY)
684
note(0, "\"%s\" %ld/%ld", name, (long)*lines, (long)*chars);
685
return 0;
686
}
687
688
/*
689
* Low level for get/Get
690
*/
691
static int
692
get1(char** argv, unsigned long flags)
693
{
694
register struct part* ap;
695
register int i;
696
register char* s;
697
char* name;
698
char* a;
699
char* e;
700
int n;
701
int r;
702
703
if (state.msg.dot < state.msg.list || state.msg.dot >= state.msg.list + state.msg.count) {
704
note(0, "No current message");
705
return 1;
706
}
707
if (state.folder == FIMAP)
708
return imap_get1(argv, flags);
709
if (!(ap = state.part.in.head) || !state.part.in.count) {
710
note(0, "No attachments in current message");
711
return 1;
712
}
713
if (!*argv) {
714
do {
715
if (ap->count)
716
printf("(attachment %2d %s %20s \"%s\")\n", ap->count, counts(1, ap->lines, ap->size), ap->type, ap->name);
717
} while (ap = ap->next);
718
return 0;
719
}
720
if (!(a = newof(0, char, state.part.in.count, 1)))
721
note(PANIC, "Out of space");
722
s = *argv++;
723
r = 0;
724
for (;;) {
725
while (isspace(*s))
726
s++;
727
if (!*s)
728
break;
729
else if (*s == ',') {
730
s++;
731
r = 0;
732
}
733
else if (*s == '*') {
734
if (!r)
735
r = 1;
736
for (i = r; i <= state.part.in.count; i++)
737
a[i] = 1;
738
r = 0;
739
}
740
else if (*s == '-') {
741
s++;
742
r = 1;
743
}
744
else {
745
n = strtol(s, &e, 0);
746
if (n > 0 && n <= state.part.in.count) {
747
if (r) {
748
for (i = r; i <= n; i++)
749
a[i] = 1;
750
r = 0;
751
}
752
else
753
a[n] = 1;
754
}
755
else
756
{
757
note(0, "%s: invalid attachment number", s);
758
while (*e && !isspace(*e))
759
e++;
760
}
761
s = e;
762
if (*s == '-') {
763
s++;
764
r = n;
765
}
766
}
767
}
768
r = 0;
769
for (i = 1; i <= state.part.in.count; i++)
770
if (a[i]) {
771
while (ap->count != i)
772
if (!(ap = ap->next)) {
773
note(0, "%d: attachment number out of range", i);
774
r = 1;
775
goto done;
776
}
777
if (name = *argv)
778
argv++;
779
else
780
name = ap->name;
781
if (getatt(ap, name, flags, NiL, NiL))
782
r = 1;
783
}
784
done:
785
free(a);
786
return r;
787
}
788
789
/*
790
* Get an attachment from the current message.
791
* Execute content view command if found.
792
*/
793
int
794
get(char** argv)
795
{
796
return get1(argv, GDISPLAY|GMIME);
797
}
798
799
/*
800
* Get an attachment from the current message.
801
* Don't execute content view command.
802
*/
803
int
804
Get(char** argv)
805
{
806
return get1(argv, GDISPLAY);
807
}
808
809
/*
810
* Low level for split.
811
*/
812
static int
813
split1(char* str, Dt_t** ignore, long num, char* dir, int verbose, int flag)
814
{
815
register struct msg* mp;
816
register struct msg* ip;
817
register struct part* ap;
818
off_t lc;
819
off_t cc;
820
FILE* fp;
821
char* s;
822
char* file;
823
824
s = dir;
825
if (!(dir = expand(dir, 1)) || !*dir || !isdir(dir)) {
826
note(0, "\"%s\": directory argument expected", s);
827
return 1;
828
}
829
if (getmsglist(str, 0) < 0)
830
return 1;
831
for (ip = state.msg.list; ip->m_index; ip++) {
832
mp = state.msg.dot = state.msg.list + ip->m_index - 1;
833
sfprintf(state.path.buf, "%s/%d", dir, num);
834
file = struse(state.path.buf);
835
if (fp = fileopen(file, "Ew")) {
836
if (copy(mp, fp, ignore, NiL, GMIME) < 0)
837
note(SYSTEM, "%s", dir);
838
else {
839
if (verbose)
840
note(PROMPT, "%s %ld %ld %ld", file, num, (long)mp->m_lines, (long)mp->m_size);
841
if (ap = state.part.in.head) {
842
do {
843
if (!(ap->flags & PART_body)) {
844
sfprintf(state.path.buf, "%s/%d-%d", dir, num, ap->count);
845
file = struse(state.path.buf);
846
if (!getatt(ap, file, 0, &lc, &cc) && verbose)
847
note(PROMPT, " %d-%d %s %s %ld %ld", num, ap->count, ap->name, ap->type, (long)lc, (long)cc);
848
}
849
} while (ap = ap->next);
850
}
851
if (verbose)
852
note(0, "");
853
msgflags(mp, flag, 0);
854
}
855
fileclose(fp);
856
}
857
touchmsg(mp);
858
num++;
859
}
860
state.msg.mh.next = num;
861
return 0;
862
}
863
864
/*
865
* Split messages into idividual files.
866
* low level for split and Split
867
*/
868
static int
869
split0(char* str, Dt_t** ignore, int flag)
870
{
871
long num;
872
int f;
873
char* file;
874
char* start;
875
char* e;
876
877
if (!(file = snarf(str, &f)) && f < 0) {
878
note(0, "file argument expected");
879
return 1;
880
}
881
if (!(start = snarf(str, &f))) {
882
note(0, "numeric argument expected");
883
return 1;
884
}
885
if ((num = strtol(start, &e, 0)) < 0 || *e) {
886
note(0, "\"%s\": numeric argument expected", start);
887
return 1;
888
}
889
return split1(str, ignore, num, file, 1, flag);
890
}
891
892
/*
893
* Split messages into idividual files.
894
* Ignore all headers.
895
*/
896
int
897
Split(char* str)
898
{
899
return split0(str, &state.ignoreall, MSAVE);
900
}
901
902
/*
903
* Split messages into idividual files.
904
* Keep all headers.
905
*/
906
int
907
split(char* str)
908
{
909
return split0(str, NiL, MSAVE);
910
}
911
912
/*
913
* Update the mail file with any new messages that have
914
* come in since we started reading mail.
915
*/
916
int
917
incorporate(void)
918
{
919
if (state.folder == FMH) {
920
int sawcom = 0;
921
long count;
922
long dot;
923
long next;
924
925
count = state.msg.count;
926
next = state.msg.mh.next;
927
sawcom = state.sawcom;
928
dot = state.msg.dot - state.msg.list;
929
state.incorporating = 1;
930
if (!setfolder("%")) {
931
split1("*", NiL, next, state.path.prev, 0, MSAVE);
932
if (!setfolder("#")) {
933
folderinfo(count);
934
state.msg.dot = state.msg.list + ((dot < 0) ? 0 : dot);
935
}
936
}
937
state.incorporating = 0;
938
state.sawcom = sawcom;
939
}
940
else {
941
int eof;
942
int n;
943
944
eof = (state.msg.dot + 1) >= state.msg.list + state.msg.count;
945
if ((n = incfile()) < 0)
946
note(0, "The \"%s\" command failed", state.cmd->c_name);
947
else if (!n)
948
note(0, "No new mail");
949
else {
950
state.msg.dot = folderinfo(state.msg.count - n);
951
if (eof)
952
state.sawcom = 0;
953
}
954
}
955
return 0;
956
}
957
958