]> diplodocus.org Git - nmh/blob - docs/historical/mh-jun-1982/progs/repl.c
Replaced use of snprintf() with memcpy()/memmove().
[nmh] / docs / historical / mh-jun-1982 / progs / repl.c
1 #ifdef COMMENT
2 Proprietary Rand Corporation, 1981.
3 Further distribution of this software
4 subject to the terms of the Rand
5 license agreement.
6 #endif
7
8 #include <whoami.h>
9 #include "../mh.h"
10 #include <stdio.h>
11 #include <signal.h>
12 #include <strings.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include "../adrparse.h"
16
17 #define ERRHOST "?????"
18 /*#define NEWS 1*/
19
20 #define NOUSE 0
21
22 /* #define TEST 1 */
23
24 struct swit anyl[] = {
25 "no", 0,
26 "yes", 0,
27 "list", 0,
28 0
29 };
30
31 struct swit aleqs[] = {
32 "list", 0, /* 0 */
33 "edit [<editor>]", 0, /* 1 */
34 "quit [delete]", 0, /* 2 */
35 "send [switches]", 0, /* 3 */
36 0
37 };
38
39 short anot;
40 #define OUTPUTLINELEN 72
41 short outputlinelen = OUTPUTLINELEN;
42 short ccme = 1;
43 struct msgs *mp;
44 char *ed;
45 short format = -1; /* Default to re-format optionally*/
46 short inplace; /* preserve links in anno */
47 short debug;
48 char *badaddrs;
49
50 struct swit switches[] = {
51 "annotate", 0, /* 0 */
52 "noannotate", 0, /* 1 */
53 "ccme", -1, /* 2 */
54 "noccme", -1, /* 3 */
55 "editor editor", 0, /* 4 */
56 "format", 0, /* 5 */
57 "noformat", 0, /* 6 */
58 "inplace", 0, /* 7 */
59 "noinplace", 0, /* 8 */
60 "width", 0, /* 9 */
61 "help", 4, /*10 */
62 "debug", -5, /*11 */
63 0, 0
64 };
65
66 char *ltrim();
67 char *rtrim();
68 char *niceadd();
69 char *fix();
70 char *addr();
71
72
73 /*ARGSUSED*/
74 main(argc, argv)
75 char *argv[];
76 {
77 char *folder, *msg, *maildir;
78 register char *cp, **ap, **argp;
79 char *arguments[50];
80
81 invo_name = argv[0];
82 #ifdef NEWS
83 m_news();
84 #endif
85 msg = 0; anot = 0; folder = 0;
86
87 cp = r1bindex(argv[0], '/');
88 if((cp = m_find(cp)) != NULL) {
89 ap = brkstring(cp = getcpy(cp), " ", "\n");
90 ap = copyip(ap, arguments);
91 } else
92 ap = arguments;
93 VOID copyip(argv+1, ap);
94 argp = arguments;
95 while(cp = *argp++) {
96 if(*cp == '-')
97 switch(smatch(++cp, switches)) {
98 case -2:ambigsw(cp, switches); /* ambiguous */
99 goto leave;
100 /* unknown */
101 case -1:fprintf(stderr, "repl: -%s unknown\n", cp);
102 goto leave;
103 case 0: anot = 1; continue; /* -annotate */
104 case 1: anot = 0; continue; /* -noannotate */
105 case 2: ccme = 1; continue; /* -ccme */
106 case 3: ccme = 0; continue; /* -noccme */
107 case 4: if(!(ed = *argp++)) { /* -editor */
108 missing: fprintf(stderr, "repl: Missing argument for %s switch\n", argp[-2]);
109 goto leave;
110 }
111 continue;
112 case 5: format = 1; continue; /* -format */
113 case 6: format = 0; continue; /* -noformat */
114 case 7: inplace = 1; continue; /* -inplace */
115 case 8: inplace = 0; continue; /* -noinplace */
116 case 9: if(!(cp = *argp++) || *cp == '-')
117 goto missing;
118 outputlinelen = atoi(cp); continue;
119 /* -help */
120 case 10:help("repl [+folder] [msg] [switches]",
121 switches);
122 goto leave;
123 case 11:debug++; continue; /* -debug */
124
125 }
126 if(*cp == '+') {
127 if(folder) {
128 fprintf(stderr, "Only one folder at a time.\n");
129 goto leave;
130 } else
131 folder = path(cp+1, TFOLDER);
132 } else if(msg) {
133 fprintf(stderr, "Only one message per reply.\n");
134 goto leave;
135 } else
136 msg = cp;
137 }
138 if(!m_find("path")) free(path("./", TFOLDER));
139 if(!msg)
140 msg = "cur";
141 if(!folder)
142 folder = m_getfolder();
143 maildir = m_maildir(folder);
144 if(chdir(maildir) < 0) {
145 fprintf(stderr, "Can't chdir to: ");
146 perror(maildir);
147 goto leave;
148 }
149 if(!(mp = m_gmsg(folder))) {
150 fprintf(stderr, "Can't read folder!?\n");
151 goto leave;
152 }
153 if(mp->hghmsg == 0) {
154 fprintf(stderr, "No messages in \"%s\".\n", folder);
155 goto leave;
156 }
157 if(!m_convert(msg))
158 goto leave;
159 if(mp->numsel == 0) {
160 fprintf(stderr, "repl: pepperoni pizza\n");/* never get here */
161 goto leave;
162 }
163 if(mp->numsel > 1) {
164 fprintf(stderr, "Only one message at a time.\n");
165 goto leave;
166 }
167 m_replace(pfolder, folder);
168 if(mp->lowsel != mp->curmsg)
169 m_setcur(mp->lowsel);
170 repl(getcpy(m_name(mp->lowsel)));
171 leave:
172 m_update();
173 done(0);
174 }
175
176 char *mn_rep;
177
178 repl(msg)
179 char *msg;
180 {
181 register char *cp;
182 register int i;
183 FILE *in, *out;
184 char name[NAMESZ], field[BUFSIZ];
185 char *drft, *msgid, *replto, *from, *sub, *date, *sender, *to, *cc;
186 int state;
187 int pid, wpid;
188 char **argp;
189 struct mailname *mnp = 0;
190 struct stat stbuf;
191
192 /***/if(debug) printf("repl(%s)\n", msg);
193 if((in = fopen(msg, "r")) == NULL) {
194 fprintf(stderr, "Can't open "); perror(msg);
195 return;
196 }
197 drft = m_maildir(draft);
198 /***/if(debug) printf("drft=%s\n", drft);
199 if(stat(drft, &stbuf) != -1) {
200 cp = concat("\"", drft, "\" exists; delete? ", 0);
201 while((i = gans(cp, anyl)) == 2)
202 VOID showfile(drft);
203 if(!i)
204 return;
205 free(cp);
206 }
207 if((out = fopen(drft, "w")) == NULL) {
208 fprintf(stderr, "Can't create \"%s\".\n", drft);
209 return;
210 }
211 VOID chmod(drft, m_gmprot());
212
213 state = FLD;
214 to = cc = sender = replto = msgid = from = sub = date = 0;
215
216 for(;;) {
217
218 switch(state = m_getfld(state, name, field, sizeof field, in)) {
219
220 case FLD:
221 case FLDEOF:
222 case FLDPLUS:
223 if(uleq(name, "from")) {
224 if(state == FLD && from) from = add(",",from);
225 from = add(field, from);
226 }
227 if(uleq(name, "cc")) {
228 if(state == FLD && cc) cc = add(",",cc);
229 cc = add(field, cc);
230 }
231 if(uleq(name, "subject"))
232 sub = add(field, sub);
233 if(uleq(name, "date"))
234 date = add(field, date);
235 if(uleq(name, "to")) {
236 if(state == FLD && to) to = add(",",to);
237 to = add(field, to);
238 }
239 if(uleq(name, "message-id"))
240 msgid = add(field, msgid);
241 if(uleq(name, "reply-to")) {
242 if(state == FLD && replto) replto = add(",",replto);
243 replto = add(field, replto);
244 }
245 if(uleq(name, "sender")) {
246 if(state == FLD && sender) sender = add(",",sender);
247 sender = add(field, sender);
248 }
249 if(state == FLDEOF)
250 goto done;
251 break;
252
253 case BODY:
254 case BODYEOF:
255 case FILEEOF:
256 goto done;
257
258 default:
259 fprintf(stderr, "getfld returned %d\n", state);
260 return;
261 }
262
263 }
264
265 done:
266 VOID fclose(in);
267
268 if(!(sender || from)) {
269 fprintf(stderr, "repl: No Sender or From!?\n");
270 return;
271 }
272
273 /* Pick up replacement host from "sender", else "from" */
274 #ifdef ARPANET
275 if((cp = getname(sender ? sender : from)) == 0)
276 return;
277 if((mnp = getm(cp, HOSTNAME)) == 0)
278 mn_rep = ERRHOST;
279 else {
280 if((mnp -> m_at) && ((*mnp -> m_at) == '!')) { /* UUCP address */
281 cp = stdhost((long)HOSTNUM);
282 }
283 else
284 cp = stdhost(mnp->m_hnum);
285 if(!cp) {
286 fprintf(stderr, "repl: Unknown host: %s\n", mnp->m_host);
287 return;
288 }
289 mn_rep = getcpy(cp);
290 mnfree(mnp);
291 }
292 #else
293 mn_rep = getcpy (HOSTNAME);
294 #endif
295 while(getname("")) ; /* In case multi-name from/sender */
296
297 /***/if(debug) printf("before testformats\n");
298 /* Set format flag to 0 or 1 based on actual addresses, */
299 /* provided it hasn't been explicitly set */
300
301 if(format == -1 && *mn_rep == '?') /* Oops, error in sender/from.*/
302 format = 1; /* Format! Use replacement host ERRHOST */
303 if(format == -1) testformat(sender);
304 if(format == -1) testformat(from);
305 if(format == -1) testformat(replto);
306 if(format == -1) testformat(to);
307 if(format == -1) testformat(cc);
308 if(format == -1) format = 0; /* All LOCAL--don't format! */
309
310 /***/if(debug) printf("after testformats\n");
311 if(!(from || replto)) {
312 fprintf(stderr, "No one to reply to!!!\n");
313 return;
314 }
315 outfmt(out, replto ? replto : from, "To", 0);
316
317 if(to && cc) /* Combine to & cc data */
318 to = add(" ,", to);
319 if(cc)
320 to = add(cc, to);
321 outfmt(out, to, "Cc", 1);
322
323 if(sub) { /* Subject: Re: */
324 fprintf(out, "Subject: ");
325 if(*sub == ' ') sub++;
326 if((sub[0] != 'R' && sub[0] != 'r') ||
327 (sub[1] != 'E' && sub[1] != 'e') ||
328 sub[2] != ':')
329 fprintf(out, "Re: ");
330 fprintf(out, sub);
331 }
332 if(date) { /* In-reply-to: */
333 date[strlen(date)-1] = '.';
334 if(*date == ' ') date++;
335 fprintf(out, "In-reply-to: Your message of %s\n", date);
336 if(msgid) {
337 if(*msgid == ' ') msgid++;
338 fprintf(out, " %s", msgid);
339 }
340 }
341 fprintf(out, "----------\n");
342 if(badaddrs)
343 fprintf(out, "\nREPL: CANT CONSTRUCT:\n%s\n", badaddrs);
344 if(fclose(out) == EOF) {
345 fprintf(stderr, "reply: Write error on ");
346 perror(drft);
347 return;
348 }
349 if(!debug)
350 if(m_edit(&ed, drft, NOUSE, msg) < 0)
351 return;
352 #ifdef TEST
353 fprintf(stderr, "!! Test Version of SEND Being Run !!\n");
354 fprintf(stderr, " Send verbose !\n\n");
355 #endif
356
357 for(;;) {
358 if(!(argp = getans("\nWhat now? ", aleqs))) {
359 VOID unlink("@");
360 return;
361 }
362 switch(smatch(*argp, aleqs)) {
363 case 0: VOID showfile(drft); /* list */
364 break;
365
366 case 1: if(*++argp) /* edit */
367 ed = *argp;
368 if(m_edit(&ed, drft, NOUSE, msg) == -1)
369 return;
370 break;
371
372 case 2: if(*++argp && (*argp[0] == 'd' || /* quit */
373 (*argp[0]=='-' && *argp[1]=='d')))
374 if(unlink(drft) == -1) {
375 fprintf(stderr, "Can't unlink %s ", drft);
376 perror("");
377 }
378 return;
379
380 case 3: /* send */
381 if(!mp->msgflags&READONLY) { /* annotate first */
382 if(anot > 0) {
383 while((pid = fork()) == -1) sleep(5);
384 if(pid) {
385 while((wpid=wait((int *)NULL))!= -1
386 && wpid!= pid);
387 if(stat(drft, &stbuf) == -1)
388 annotate(msg, "Replied", "", inplace);
389 return;
390 }
391 }
392 }
393 VOID m_send(++argp, drft);
394 return;
395
396 default:fprintf(stderr, "repl: illegal option\n"); /*##*/
397 break;
398 }
399 }
400 }
401
402
403 outfmt(out, str, fn, chk)
404 FILE *out;
405 char *str, *fn;
406 int chk;
407 {
408 register char *cp;
409 register struct mailname *mnp = 0;
410 short ccoutput = 0, linepos = 0, len;
411
412 /***/if(debug)printf("outfmt mn_rep=%s\n", mn_rep);
413 while(cp = getname(str)) {
414 if(mnp) mnfree(mnp);
415 /***/if(debug)printf("Parse '%s'\n",cp);
416
417 /* If couldn't find foreign default host due to sender/from */
418 /* parse error, hand adrparse HOSTNAME for the time. */
419
420 if((mnp = getm(cp, *mn_rep == '?' ? HOSTNAME : mn_rep)) == 0){
421 char buf[512];
422 /* Can't parse. Add to badlist. */
423 VOID sprintf(buf, " %s: %s\n", fn, cp);
424 badaddrs = add(buf, badaddrs);
425 continue;
426 } else if(*mn_rep == '?') {
427 /*
428 * Now must distinguish between explicit-local and
429 * hostless-foreign, which parse identically
430 * because of the borrowed HOSTNAME.
431 * Kludge: If same string gives parse error when
432 * default host is ERRHOST, then original string was
433 * hostless (foreign). Otherwise original string had
434 * HOSTNAME explicitly and is local.
435 */
436 struct mailname *tmpmnp;
437
438 if(tmpmnp = getm(cp, ERRHOST))
439 mnfree(tmpmnp);
440 else
441 mnp->m_host = getcpy(ERRHOST);
442
443 }
444 /***/if(debug) printf ("Host %D\n",mnp->m_hnum);
445 if(chk && !ccme && uleq(mnp->m_mbox, getenv("USER")) &&
446 mnp->m_hnum == HOSTNUM)
447 continue;
448 if(!ccoutput) {
449 fprintf(out, "%s: ", fn);
450 linepos += (ccoutput = strlen(fn) + 2);
451 }
452 if((format && *mn_rep != '?')|| ((mnp->m_at && *mnp->m_at != '!') &&
453 (mnp->m_hnum != HOSTNUM)) ) {
454
455 /***/if(debug) printf ("That's not %d, so format it (name %s)\n",
456 HOSTNUM, HOSTNAME);
457 cp = adrformat(mnp,HOSTNAME);
458 /***/if(debug) printf ("Formatting produces '%s'\n",cp);
459 }
460 else if (format && *mn_rep == '?') {
461 cp = adrformat(mnp, mn_rep);
462 }
463 else
464 cp = mnp->m_text;
465 len = strlen(cp);
466 if(linepos != ccoutput)
467 if(len + linepos + 2 > outputlinelen) {
468 fprintf(out, ",\n%*s", ccoutput, "");
469 linepos = ccoutput;
470 } else {
471 fputs(", ", out);
472 linepos += 2;
473 }
474 fputs(cp, out);
475 linepos += len;
476 }
477 if(mnp) mnfree(mnp);
478 if(linepos) putc('\n', out);
479 }
480
481
482 testformat(str)
483 char *str;
484 {
485 register struct mailname *mnp;
486 register char *cp;
487
488 if(str)
489 while(cp = getname(str)) {
490 if(mnp = getm(cp, mn_rep)) {
491 if((mnp->m_hnum != HOSTNUM) &&
492 (mnp->m_at) && (*mnp->m_at != '!'))
493 format = 1;
494 mnfree(m