4 #include "../smtp/smtp.h"
5 #include "../smtp/rfc822.tab.h"
7 /* global to this file */
11 #define VMLIMIT (64*1024)
12 #define MSGLIMIT (128*1024*1024)
14 int received; /* from rfc822.y */
16 static String* getstring(Node *p);
17 static String* getaddr(Node *p);
20 default_from(message *mp)
24 cp = getenv("upasname");
30 s_append(mp->sender, cp);
32 s_append(mp->sender, lp);
33 s_append(mp->date, thedate());
42 mp = (message *)mallocz(sizeof(message), 1);
48 mp->replyaddr = s_new();
61 sysremove(s_to_c(mp->tmp));
68 s_free(mp->havesender);
69 s_free(mp->havereplyto);
70 s_free(mp->havesubject);
74 /* read a message into a temp file , return an open fd to it */
76 m_read_to_file(Biobuf *fp, message *mp)
85 * create temp file to be remove on close
87 abspath("mtXXXXXX", UPASTMP, file);
89 if((fd = syscreate(s_to_c(file), ORDWR|ORCLOSE, 0600))<0){
96 * read the rest into the temp file
98 while((n = Bread(fp, buf, sizeof(buf))) > 0){
99 if(write(fd, buf, n) != n){
104 if(mp->size > MSGLIMIT){
114 /* get the first address from a node */
118 for(; p; p = p->next)
120 return s_copy(s_to_c(p->s));
124 /* get the text of a header line minus the field name */
134 for(p = p->next; p; p = p->next){
136 s_append(s, s_to_c(p->s));
142 s_append(s, s_to_c(p->white));
148 static char *fieldname[] =
152 [RESENT_DATE-WORD] "RESENT_DATE",
153 [RETURN_PATH-WORD] "RETURN_PATH",
155 [SENDER-WORD] "SENDER",
156 [REPLY_TO-WORD] "REPLY_TO",
157 [RESENT_FROM-WORD] "RESENT_FROM",
158 [RESENT_SENDER-WORD] "RESENT_SENDER",
159 [RESENT_REPLY_TO-WORD] "RESENT_REPLY_TO",
160 [SUBJECT-WORD] "SUBJECT",
164 [RESENT_TO-WORD] "RESENT_TO",
165 [RESENT_CC-WORD] "RESENT_CC",
166 [RESENT_BCC-WORD] "RESENT_BCC",
167 [REMOTE-WORD] "REMOTE",
168 [PRECEDENCE-WORD] "PRECEDENCE",
169 [MIMEVERSION-WORD] "MIMEVERSION",
170 [CONTENTTYPE-WORD] "CONTENTTYPE",
171 [MESSAGEID-WORD] "MESSAGEID",
172 [RECEIVED-WORD] "RECEIVED",
173 [MAILER-WORD] "MAILER",
174 [BADTOKEN-WORD] "BADTOKEN"
178 /* fix 822 addresses */
180 rfc822cruft(message *mp)
188 * parse headers in in-core part
190 yyinit(s_to_c(mp->body), s_len(mp->body));
191 mp->rfc822headers = 0;
193 mp->rfc822headers = 1;
194 mp->received = received;
197 * remove equivalent systems in all addresses
200 cp = s_to_c(mp->body);
201 for(f = firstfield; f; f = f->next){
202 if(f->node->c == MIMEVERSION)
204 if(f->node->c == FROM)
205 mp->havefrom = getaddr(f->node);
206 if(f->node->c == SENDER)
207 mp->havesender = getaddr(f->node);
208 if(f->node->c == REPLY_TO)
209 mp->havereplyto = getaddr(f->node);
212 if(f->node->c == DATE)
214 if(f->node->c == SUBJECT)
215 mp->havesubject = getstring(f->node);
216 if(f->node->c == PRECEDENCE && f->node->next && f->node->next->next){
217 s = f->node->next->next->s;
218 if(s && (strcmp(s_to_c(s), "bulk") == 0
219 || strcmp(s_to_c(s), "Bulk") == 0))
222 for(p = f->node; p; p = p->next){
225 cp = skipequiv(s_to_c(p->s));
228 s_append(body, s_to_c(p->s));
234 s_append(body, s_to_c(p->white));
237 s_append(body, "\n");
240 if(*s_to_c(body) == 0){
246 s_append(body, "\n");
247 s_memappend(body, cp, s_len(mp->body) - (cp - s_to_c(mp->body)));
251 mp->size += s_len(body) - s_len(mp->body);
256 /* read in a message, interpret the 'From' header */
258 m_read(Biobuf *fp, int rmail, int interactive)
268 /* parse From lines if remote */
270 /* get remote address */
271 String *sender=s_new();
274 rfprog = regcomp(REMFROMRE);
276 while(s_read_line(fp, s_restart(mp->body)) != 0) {
277 memset(subexp, 0, sizeof(subexp));
278 if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){
282 fprog = regcomp(FROMRE);
283 memset(subexp, 0, sizeof(subexp));
284 if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0)
287 append_match(subexp, s_restart(sender), SENDERMATCH);
288 append_match(subexp, s_restart(mp->date), DATEMATCH);
291 append_match(subexp, s_restart(sender), REMSENDERMATCH);
292 append_match(subexp, s_restart(mp->date), REMDATEMATCH);
293 if(subexp[REMSYSMATCH].s.sp!=subexp[REMSYSMATCH].e.ep){
294 append_match(subexp, mp->sender, REMSYSMATCH);
295 s_append(mp->sender, "!");
299 s_append(mp->sender, s_to_c(sender));
303 if(*s_to_c(mp->sender)=='\0')
306 /* if sender address is unreturnable, treat message as bulk mail */
307 if(!returnable(s_to_c(mp->sender)))
311 if(interactive && !rmail){
312 /* user typing on terminal: terminator == '.' or EOF */
314 line = s_read_line(fp, mp->body);
317 if (strcmp(".\n", line)==0) {
319 *mp->body->ptr = '\0';
323 mp->size = mp->body->ptr - mp->body->base;
326 * read up to VMLIMIT bytes (more or less) into main memory.
327 * if message is longer put the rest in a tmp file.
329 mp->size = mp->body->ptr - mp->body->base;
330 n = s_read(fp, mp->body, VMLIMIT);
337 if(m_read_to_file(fp, mp) < 0){
338 perror("m_read_to_file");
345 * ignore 0 length messages from a terminal
347 if (!rmail && mp->size == 0)
355 /* return a piece of message starting at `offset' */
357 m_get(message *mp, long offset, char **pp)
359 static char buf[4*1024];
364 if(offset >= mp->size)
368 * are we in the virtual memory portion?
370 if(offset < s_len(mp->body)){
371 *pp = mp->body->base + offset;
372 return mp->body->ptr - mp->body->base - offset;
376 * read it from the temp file
378 offset -= s_len(mp->body);
381 if(seek(mp->fd, offset, 0)<0)
384 return read(mp->fd, buf, sizeof buf);
387 /* output the message body without ^From escapes */
389 m_noescape(message *mp, Biobuf *fp)
395 for(offset = 0; offset < mp->size; offset += n){
396 n = m_get(mp, offset, &p);
401 if(Bwrite(fp, p, n) < 0)
408 * Output the message body with '^From ' escapes.
409 * Ensures that any line starting with a 'From ' gets a ' ' stuck
413 m_escape(message *mp, Biobuf *fp)
421 for(offset = 0; offset < mp->size; offset += n){
422 n = m_get(mp, offset, &start);
429 for(end = p+n; p < end; p += m){
430 np = memchr(p, '\n', end-p);
432 Bwrite(fp, p, end-p);
436 if(m > 5 && strncmp(p, "From ", 5) == 0)
446 printfrom(message *mp, Biobuf *fp)
451 if(!returnable(s_to_c(mp->sender)))
452 return Bprint(fp, "From: Postmaster\n");
454 s = username(mp->sender);
457 s_append(s, s_to_c(mp->sender));
460 s = s_copy(s_to_c(mp->sender));
462 s = unescapespecial(s);
463 rv = Bprint(fp, "From: %s\n", s_to_c(s));
476 tm = localtime(time(0));
477 mindiff = tm->tzoff/60;
479 /* if not in my timezone, don't change anything */
480 if(strcmp(tm->zone, z) != 0)
489 sprint(x, "%c%.2d%.2d", s, mindiff/60, mindiff%60);
498 for(p = s_to_c(s); *p; p++)
505 printutf8mime(Biobuf *b)
507 Bprint(b, "MIME-Version: 1.0\n");
508 Bprint(b, "Content-Type: text/plain; charset=\"UTF-8\"\n");
509 Bprint(b, "Content-Transfer-Encoding: 8bit\n");
512 /* output a message */
514 m_print(message *mp, Biobuf *fp, char *remote, int mbox)
516 String *date, *sender;
520 sender = unescapespecial(s_clone(mp->sender));
523 if(print_remote_header(fp,s_to_c(sender),s_to_c(mp->date),remote) < 0){
528 if(print_header(fp, s_to_c(sender), s_to_c(mp->date)) < 0){
534 if(!rmail && !mp->havedate){
535 /* add a date: line Date: Sun, 19 Apr 1998 12:27:52 -0400 */
536 date = s_copy(s_to_c(mp->date));
537 n = getfields(s_to_c(date), f, 6, 1, " \t");
539 Bprint(fp, "Date: %s, %s %s %s %s %s\n", f[0], f[2], f[1],
540 f[5], f[3], rewritezone(f[4]));
542 if(!rmail && !mp->havemime && isutf8(mp->body))
545 /* add the to: line */
546 if (Bprint(fp, "%s\n", s_to_c(mp->to)) < 0)
548 /* add the from: line */
549 if (!mp->havefrom && printfrom(mp, fp) < 0)
551 if(!mp->rfc822headers && *s_to_c(mp->body) != '\n')
552 if (Bprint(fp, "\n") < 0)
555 /* add the from: line */
556 if (!mp->havefrom && printfrom(mp, fp) < 0)
558 if(!mp->rfc822headers && *s_to_c(mp->body) != '\n')
559 if (Bprint(fp, "\n") < 0)
564 return m_noescape(mp, fp);
565 return m_escape(mp, fp);
568 /* print just the message body */
570 m_bprint(message *mp, Biobuf *fp)
572 return m_noescape(mp, fp);