Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/mailx/cmd1.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the BSD package *
4
*Copyright (c) 1978-2012 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
* User commands.
73
*/
74
75
#include "mailx.h"
76
77
/*
78
* Print out the header of a specific message.
79
* This is a slight improvement to the standard one.
80
*/
81
static void
82
printhead(int mesg, int who)
83
{
84
register struct msg* mp;
85
char* name;
86
char* sizes;
87
char* subjline;
88
int curind;
89
int dispc;
90
int subjlen;
91
struct headline hl;
92
char pbuf[LINESIZE];
93
char headline[LINESIZE];
94
95
mp = state.msg.list + mesg - 1;
96
readline(setinput(mp), headline, sizeof(headline));
97
subjline = grab(mp, GSUB, NiL);
98
curind = state.msg.dot == mp && !state.var.justheaders ? '>' : ' ';
99
parse(mp, headline, &hl, pbuf, sizeof(pbuf));
100
if (mp->m_flag & MBOX)
101
dispc = 'M';
102
else if (mp->m_flag & MPRESERVE)
103
dispc = 'P';
104
else if (mp->m_flag & MSAVE)
105
dispc = '*';
106
else if (mp->m_flag & MSPAM)
107
{
108
dispc = 'X';
109
if (subjline && state.var.spamsubhead)
110
{
111
register int c;
112
register char* s;
113
register char* t;
114
register char* u;
115
116
s = t = subjline;
117
while (c = *s++)
118
{
119
if (!isalnum(c) && c == *s)
120
{
121
while (*s == c)
122
s++;
123
for (u = s; *u && *u != c; u++);
124
if (*u == c && *(u + 1) == c)
125
{
126
for (s = u; *s == c; s++);
127
if (t == subjline)
128
while (isspace(*s))
129
s++;
130
continue;
131
}
132
}
133
*t++ = c;
134
}
135
*t = 0;
136
}
137
}
138
else if (!(mp->m_flag & (MREAD|MNEW)))
139
dispc = 'U';
140
else if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
141
dispc = 'N';
142
else
143
dispc = who ? 'R' : ' ';
144
if (who)
145
{
146
if (!(name = grab(mp, GSENDER|GDISPLAY, NiL)))
147
name = hl.l_from;
148
if (!state.var.domain || strchr(name, '@'))
149
printf("%c %s\n", dispc, name);
150
else
151
printf("%c %s@%s\n", dispc, name, state.var.domain);
152
}
153
else
154
{
155
name = grab(mp, (state.var.news ? GNEWS : state.var.showto && sender(state.var.user, mesg) ? GTO : GREPLY)|GDISPLAY, NiL);
156
sizes = counts(!!state.var.news, mp->m_lines, mp->m_size);
157
subjlen = state.screenwidth - 50 - strlen(sizes);
158
if (subjline && subjlen >= 0)
159
printf("%c%c%3d %-20.20s %16.16s %s %.*s\n",
160
curind, dispc, mesg, name, hl.l_date, sizes,
161
subjlen, subjline);
162
else
163
printf("%c%c%3d %-20.20s %16.16s %s\n",
164
curind, dispc, mesg, name, hl.l_date, sizes);
165
}
166
}
167
168
/*
169
* Print the current active headings.
170
* Don't change dot if invoker didn't give an argument.
171
*/
172
173
int
174
headers(struct msg* msgvec)
175
{
176
register int n;
177
register int mesg;
178
register int flag;
179
register struct msg* mp;
180
int m;
181
182
if (state.var.justfrom) {
183
flag = 1;
184
mp = state.msg.list;
185
if (state.var.justfrom > 0 && state.var.justfrom < state.msg.count)
186
mp += state.msg.count - state.var.justfrom;
187
m = state.msg.count + 1;
188
}
189
else {
190
flag = 0;
191
n = msgvec->m_index;
192
if ((m = state.var.screen) <= 0 && (m = state.msg.count) <= 0)
193
m = 1;
194
if (n != 0)
195
state.scroll = (n - 1) / m;
196
if (state.scroll < 0)
197
state.scroll = 0;
198
mp = state.msg.list + state.scroll * m;
199
if (mp >= state.msg.list + state.msg.count)
200
mp = state.msg.list + state.msg.count - m;
201
if (mp < state.msg.list)
202
mp = state.msg.list;
203
if (state.msg.dot != state.msg.list + n - 1)
204
state.msg.dot = mp;
205
}
206
for (mesg = mp - state.msg.list; mp < state.msg.list + state.msg.count; mp++) {
207
mesg++;
208
if (mp->m_flag & (MDELETE|MNONE))
209
continue;
210
CALL(printhead)(mesg, !!state.var.justfrom);
211
if (++flag >= m)
212
break;
213
}
214
if (!flag) {
215
note(0, "No more mail");
216
return 1;
217
}
218
return 0;
219
}
220
221
/*
222
* Scroll to the next/previous screen
223
*/
224
int
225
scroll(char* arg)
226
{
227
register int s;
228
229
s = state.scroll;
230
switch (*arg) {
231
case 0:
232
case '+':
233
s++;
234
if (s * state.var.screen > state.msg.count) {
235
note(0, "On last screenful of messages");
236
return 0;
237
}
238
state.scroll = s;
239
break;
240
241
case '-':
242
if (--s < 0) {
243
note(0, "On first screenful of messages");
244
return 0;
245
}
246
state.scroll = s;
247
break;
248
249
default:
250
note(0, "Unrecognized scrolling command \"%s\"", arg);
251
return 1;
252
}
253
state.msg.list->m_index = 0;
254
return headers(state.msg.list);
255
}
256
257
/*
258
* from or From
259
*/
260
static int
261
from2(struct msg* msgvec, int who)
262
{
263
register struct msg* ip;
264
265
for (ip = msgvec; ip->m_index; ip++)
266
CALL(printhead)(ip->m_index, who);
267
if (--ip >= msgvec)
268
state.msg.dot = state.msg.list + ip->m_index - 1;
269
return 0;
270
}
271
272
/*
273
* Print out the headlines for each message
274
* in the passed message list.
275
*/
276
int
277
from(struct msg* msgvec)
278
{
279
return from2(msgvec, 0);
280
}
281
282
/*
283
* Print out the status, message number, and sender
284
* in the passed message list.
285
*/
286
int
287
From(struct msg* msgvec)
288
{
289
return from2(msgvec, 1);
290
}
291
292
/*
293
* Print out the value of dot.
294
*/
295
int
296
dot(void)
297
{
298
note(0, "%d", state.msg.dot - state.msg.list + 1);
299
return 0;
300
}
301
302
/*
303
* Print out all the possible commands.
304
*/
305
int
306
list(void)
307
{
308
register int i;
309
register int j;
310
register int cmds;
311
register int cols;
312
register int rows;
313
314
cmds = state.cmdnum;
315
cols = 5;
316
rows = (cmds + cols - 1) / cols;
317
for (i = 0; i < rows; i++) {
318
for (j = i; j < cmds; j += rows)
319
printf("%-15s", state.cmdtab[j].c_name);
320
putchar('\n');
321
}
322
return 0;
323
}
324
325
/*
326
* Type out the messages requested.
327
*/
328
static int
329
type1(struct msg* msgvec, Dt_t** ignore, int page, unsigned long flags)
330
{
331
register struct msg* ip;
332
register struct msg* mp;
333
int nlines;
334
int sig;
335
FILE* obuf;
336
337
obuf = stdout;
338
if (sig = setjmp(state.jump.sigpipe))
339
resume(sig);
340
else {
341
if (!state.more.discipline && state.var.interactive && (page || state.var.crt)) {
342
nlines = 0;
343
if (!page) {
344
for (ip = msgvec; ip->m_index; ip++)
345
nlines += state.msg.list[ip->m_index - 1].m_lines;
346
}
347
if (page || nlines > state.var.crt) {
348
if (!(obuf = pipeopen(state.var.pager, "Jw")))
349
obuf = stdout;
350
}
351
}
352
for (ip = msgvec; ip->m_index; ip++) {
353
mp = state.msg.dot = state.msg.list + ip->m_index - 1;
354
touchmsg(mp);
355
if (!state.var.quiet)
356
fprintf(obuf, "Message %d:\n", ip->m_index);
357
copy(mp, obuf, ignore, NiL, flags);
358
}
359
}
360
if (obuf != stdout)
361
fileclose(obuf);
362
return 0;
363
}
364
365
/*
366
* Paginate messages, honor ignored fields.
367
*/
368
int
369
more(struct msg* msgvec)
370
{
371
return type1(msgvec, &state.ignore, 1, GMIME);
372
}
373
374
/*
375
* Paginate messages, even printing ignored fields.
376
*/
377
int
378
More(struct msg* msgvec)
379
{
380
381
return type1(msgvec, NiL, 1, 0);
382
}
383
384
/*
385
* Type out messages, honor ignored fields.
386
*/
387
int
388
type(struct msg* msgvec)
389
{
390
391
return type1(msgvec, &state.ignore, 0, GMIME);
392
}
393
394
/*
395
* Type out messages, even printing ignored fields.
396
*/
397
int
398
Type(struct msg* msgvec)
399
{
400
401
return type1(msgvec, NiL, 0, 0);
402
}
403
404
/*
405
* Print the top so many lines of each desired message.
406
* The number of lines is taken from the variable "toplines"
407
* and defaults to 5.
408
*/
409
int
410
top(struct msg* msgvec)
411
{
412
register struct msg* ip;
413
register struct msg* mp;
414
int c;
415
int lines;
416
int lineb;
417
char linebuf[LINESIZE];
418
FILE* ibuf;
419
420
lineb = 1;
421
for (ip = msgvec; ip->m_index; ip++) {
422
mp = state.msg.list + ip->m_index - 1;
423
touchmsg(mp);
424
state.msg.dot = mp;
425
if (!state.var.quiet)
426
printf("Message %d:\n", ip->m_index);
427
ibuf = setinput(mp);
428
c = mp->m_lines;
429
if (!lineb)
430
printf("\n");
431
for (lines = 0; lines < c && lines <= state.var.toplines; lines++) {
432
if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
433
break;
434
puts(linebuf);
435
lineb = blankline(linebuf);
436
}
437
}
438
return 0;
439
}
440
441
/*
442
* List the folders the user currently has.
443
*/
444
int
445
folders(void)
446
{
447
char* cmd;
448
char dirname[LINESIZE];
449
450
if (state.folder == FIMAP)
451
return imap_folders();
452
if (getfolder(dirname, sizeof(dirname)) < 0) {
453
note(0, "No value set for \"%s\"", state.cmd->c_name);
454
return 1;
455
}
456
if (!(cmd = state.var.lister))
457
cmd = "ls";
458
run_command(cmd, 0, -1, -1, dirname, NiL, NiL);
459
return 0;
460
}
461
462
/*
463
* Pipe messages through command.
464
*/
465
int
466
cmdpipe(char* str)
467
{
468
register struct msg* mp;
469
register struct msg* ip;
470
int f;
471
char* cmd;
472
char* s;
473
char* mode;
474
off_t lc;
475
off_t cc;
476
FILE* fp;
477
478
fp = 0;
479
if (f = setjmp(state.jump.sigpipe)) {
480
resume(f);
481
if (fp)
482
fileclose(fp);
483
return 1;
484
}
485
if (!(cmd = snarf(str, &f))) {
486
if (f < 0)
487
return 1;
488
if (!(cmd = state.var.cmd)) {
489
note(0, "\"cmd\" variable not set");
490
return 1;
491
}
492
}
493
if (!f) {
494
if (!(state.msg.list->m_index = first(0, MMNORM))) {
495
note(0, "No messages to %s", cmd);
496
return 1;
497
}
498
(state.msg.list + 1)->m_index = 0;
499
}
500
else if (getmsglist(str, 0) < 0)
501
return 1;
502
if (*(s = cmd + strlen(cmd) - 1) == '&') {
503
*s = 0;
504
mode = "JNw";
505
}
506
else
507
mode = "Jw";
508
if (!(cmd = expand(cmd, 0)))
509
return 1;
510
if (!(fp = pipeopen(cmd, mode)))
511
return 1;
512
note(0, "Pipe to: \"%s\"", cmd);
513
lc = cc = 0;
514
for (ip = state.msg.list; ip->m_index; ip++) {
515
mp = state.msg.list + ip->m_index - 1;
516
touchmsg(mp);
517
if (copy(mp, fp, NiL, NiL, 0) < 0) {
518
note(SYSTEM, "\"%s\"", cmd);
519
fileclose(fp);
520
return 1;
521
}
522
if (state.var.page)
523
putc('\f', fp);
524
lc += mp->m_lines;
525
cc += mp->m_size;
526
}
527
if (fp)
528
fileclose(fp);
529
note(0, "\"%s\" %ld/%ld", cmd, (long)lc, (long)cc);
530
return 0;
531
}
532
533
/*
534
* Single quote s to fp.
535
*/
536
static void
537
quote(FILE* fp, register char* s)
538
{
539
register int c;
540
541
for (;;) {
542
switch (c = *s++) {
543
case 0:
544
break;
545
case '\'':
546
fprintf(fp, "'\\''");
547
continue;
548
default:
549
fputc(c, fp);
550
continue;
551
}
552
break;
553
}
554
}
555
556
/*
557
* Dump the blasted header fields.
558
*/
559
static int
560
blastdump(Dt_t* dt, void* object, void* context)
561
{
562
register struct name* hp = (struct name*)object;
563
564
printf("header[%s]='", hp->name);
565
quote(stdout, (char*)hp->value);
566
printf("'\n");
567
hp->flags = 0;
568
hp->value = 0;
569
return 0;
570
}
571
572
/*
573
* Low level for blast, Blast.
574
*/
575
static int
576
blast1(struct msg* msgvec, Dt_t** ignore)
577
{
578
register int n;
579
register struct msg* ip;
580
register struct msg* mp;
581
int first;
582
struct name* hp;
583
char* next;
584
char tmp[LINESIZE];
585
Dt_t* headers = 0;
586
struct parse pp;
587
588
for (ip = msgvec; ip->m_index; ip++) {
589
mp = state.msg.list + ip->m_index - 1;
590
591
/*
592
* Collect the header names and sizes.
593
*/
594
595
if (headset(&pp, mp, NiL, NiL, ignore, 0))
596
while (headget(&pp))
597
if (hp = dictsearch(&headers, pp.name, INSERT|IGNORECASE|STACK))
598
hp->flags = pp.length - (pp.data - pp.buf);
599
600
/*
601
* Collect the header values.
602
*/
603
604
if (headset(&pp, mp, NiL, NiL, ignore, 0)) {
605
printf("from='");
606
quote(stdout, pp.data);
607
printf("'\n");
608
next = tmp;
609
while (headget(&pp))
610
if (hp = dictsearch(&headers, pp.name, LOOKUP)) {
611
if (!hp->value) {
612
hp->value = (void*)next;
613
next += hp->flags + 1;
614
if (next > &tmp[sizeof(tmp)]) {
615
note(0, "Too many headers");
616
goto skip;
617
}
618
*((char*)hp->value) = 0;
619
}
620
strcat((char*)hp->value, pp.data);
621
}
622
}
623
624
/*
625
* Dump the header values.
626
*/
627
628
dictwalk(&headers, blastdump, NiL);
629
630
/*
631
* Dump the message text.
632
*/
633
634
first = 1;
635
printf("text='");
636
while (pp.count > 0 && fgets(pp.buf, sizeof(pp.buf), pp.fp)) {
637
if (n = strlen(pp.buf)) {
638
pp.count -= n;
639
pp.buf[n - 1] = 0;
640
}
641
if (first)
642
first = 0;
643
else
644
putchar('\n');
645
quote(stdout, pp.buf);
646
}
647
printf("'\n");
648
skip: ;
649
}
650
return 0;
651
}
652
653
/*
654
* Blast message into name=value pairs.
655
*/
656
int
657
blast(struct msg* msgvec)
658
{
659
return blast1(msgvec, &state.ignore);
660
}
661
662
/*
663
* Blast message into name=value pairs, including ignored fields.
664
*/
665
int
666
Blast(struct msg* msgvec)
667
{
668
return blast1(msgvec, NiL);
669
}
670
671
/*
672
* Add/delete/list content capabilities.
673
*/
674
int
675
capability(register char** argv)
676
{
677
register char* s;
678
register char* t;
679
680
if (!mime(1))
681
return 0;
682
if (!(s = *argv++))
683
mimelist(state.part.mime, stdout, NiL);
684
else {
685
if ((t = s + strlen(s)) > s && *--t == ';')
686
*t = 0;
687
else
688
t = 0;
689
if (!*argv) {
690
if (t)
691
mimeset(state.part.mime, s, MIME_REPLACE);
692
else if (!mimelist(state.part.mime, stdout, s))
693
note(0, "\"%s\": unknown capability", s);
694
}
695
else if (streq(s, "<")) {
696
while (s = *argv++)
697
if (mimeload(state.part.mime, s, MIME_REPLACE))
698
note(SYSTEM, "%s: mime load error", s);
699
}
700
else {
701
sfprintf(state.path.buf, "%s;", s);
702
while (s = *argv++)
703
sfprintf(state.path.buf, " %s", s);
704
mimeset(state.part.mime, struse(state.path.buf), MIME_REPLACE);
705
}
706
}
707
return 0;
708
}
709
710
/*
711
* Mark names.
712
*/
713
struct mark {
714
const char* name;
715
int flag;
716
int set;
717
int clear;
718
};
719
720
static const struct mark marks[] = {
721
722
"delete", MDELETE, MDELETE, 0,
723
"dot", MMARK, MMARK, 0,
724
"mbox", MBOX, MBOX|MTOUCH, MPRESERVE|MSPAM,
725
"new", MNEW, MNEW, MDELETE|MREAD|MSPAM,
726
"preserve", MPRESERVE, MPRESERVE, MBOX|MSPAM,
727
"read", MREAD, MREAD|MTOUCH|MSTATUS, MNEW,
728
"save", MSAVE, MSAVE, 0,
729
"scan", MSCAN, MSCAN, 0,
730
"spam", MSPAM, MSPAM, 0,
731
"touch", MTOUCH, MTOUCH, MPRESERVE,
732
733
};
734
735
/*
736
* Mark the indicated messages with the named mark or flags by default.
737
*/
738
static int
739
mark1(char* str, int set, int clr)
740
{
741
register struct msg* ip;
742
register struct msg* mp;
743
register const struct mark* kp;
744
register char* mark;
745
register char* next;
746
int f;
747
int no;
748
749
if ((mark = snarf(str, &f)) && isalpha(*mark)) {
750
set = clr = 0;
751
do {
752
if ((next = strchr(mark, ',')) || (next = strchr(mark, '|')))
753
*next++ = 0;
754
no = 0;
755
switch (lower(mark[0])) {
756
case 'n':
757
if (lower(mark[1]) == 'o')
758
no = 2;
759
break;
760
case 'u':
761
if (lower(mark[1]) == 'n')
762
no = 2;
763
break;
764
}
765
mark += no;
766
if (!(kp = (struct mark*)strsearch(marks, elementsof(marks), sizeof(*marks), strcasecmp, mark, NiL))) {
767
note(0, "%s: unknown mark", mark);
768
return 1;
769
}
770
if (no) {
771
set |= kp->clear;
772
clr |= kp->set;
773
}
774
else {
775
set |= kp->set;
776
clr |= kp->clear;
777
}
778
} while (mark = next);
779
}
780
else if (f < 0)
781
return 1;
782
else {
783
if (f)
784
*(mark - 1) = ' ';
785
else if (mark)
786
f = 1;
787
if (!clr) {
788
if (!set)
789
set = MMARK;
790
else
791
for (kp = marks; kp < &marks[elementsof(marks)]; kp++)
792
if (kp->flag & set) {
793
set |= kp->set;
794
clr |= kp->clear;
795
}
796
}
797
}
798
if (!f) {
799
if (!state.msg.list || !(state.msg.list->m_index = first(0, MMNORM))) {
800
note(0, "No messages to %s", state.cmd->c_name);
801
return 1;
802
}
803
(state.msg.list + 1)->m_index = 0;
804
}
805
else if (getmsglist(str, 0) < 0)
806
return 1;
807
clr |= MMARK;
808
for (mp = 0, ip = state.msg.list; ip->m_index; ip++) {
809
mp = state.msg.list + ip->m_index - 1;
810
msgflags(mp, set, clr);
811
}
812
if (mp) {
813
if (set & MMARK)
814
state.msg.dot = mp;
815
else if ((set|clr) & MSPAM) {
816
state.msg.dot = mp;
817
if (f = first(0, MDELETE|MSPAM))
818
state.msg.dot = state.msg.list + f - 1;
819
}
820
}
821
return 0;
822
}
823
824
/*
825
* Mark all given messages to the given state.
826
*/
827
int
828
mark(char* str)
829
{
830
return isupper(*state.cmd->c_name) ? mark1(str, 0, MSPAM) : mark1(str, MSPAM, 0);
831
}
832
833
/*
834
* Touch all the given messages so that they will
835
* get mboxed.
836
*/
837
int
838
cmdtouch(char* str)
839
{
840
return mark1(str, MTOUCH, 0);
841
}
842
843
/*
844
* Make sure all passed messages get mboxed.
845
*/
846
int
847
mboxit(char* str)
848
{
849
return mark1(str, MBOX, 0);
850
}
851
852
/*
853
* Preserve the named messages, so that they will be sent
854
* back to the system mailbox.
855
*/
856
int
857
preserve(char* str)
858
{
859
return mark1(str, MPRESERVE, 0);
860
}
861
862
/*
863
* Mark all given messages as unread.
864
*/
865
int
866
unread(char* str)
867
{
868
return mark1(str, MREAD, 0);
869
}
870
871
/*
872
* For unimplemented commands.
873
*/
874
int
875
notyet(char* str)
876
{
877
note(0, "\"%s\": command not implemented yet", state.cmd->c_name);
878
return 0;
879
}
880
881
/*
882
* Duplicate messages to address preserving the original senders.
883
*/
884
int
885
duplicate(char* str)
886
{
887
register struct msg* ip;
888
register struct msg* mp;
889
int f;
890
char* addr[2];
891
892
if (!(addr[0] = snarf(str, &f))) {
893
note(0, "Recipent address required");
894
return 1;
895
}
896
if (getmsglist(str, 0) < 0)
897
return 1;
898
if (state.var.debug) {
899
note(DEBUG, "%s to \"%s\"", state.cmd->c_name, addr[0]);
900
return 0;
901
}
902
addr[1] = 0;
903
for (ip = state.msg.list; ip->m_index; ip++) {
904
mp = state.msg.list + ip->m_index - 1;
905
if (sendsmtp(setinput(mp), state.var.smtp, addr, mp->m_size))
906
return 1;
907
}
908
return 0;
909
}
910
911