1 #include "common.h" 2 #include "send.h" 3 4 /* global to this file */ 5 static Reprog *rfprog; 6 static Reprog *fprog; 7 8 #define VMLIMIT (64*1024) 9 #define MSGLIMIT (128*1024*1024) 10 11 extern void 12 default_from(message *mp) 13 { 14 char *cp; 15 16 cp = getenv("upasname"); 17 if(cp) 18 s_append(mp->sender, cp); 19 else 20 s_append(mp->sender, getlog()); 21 s_append(mp->date, thedate()); 22 } 23 24 extern message * 25 m_new(void) 26 { 27 message *mp; 28 29 mp = (message *)malloc(sizeof(message)); 30 if (mp == 0) { 31 perror("message:"); 32 exit(1); 33 } 34 mp->sender = s_new(); 35 mp->replyaddr = s_new(); 36 mp->date = s_new(); 37 mp->body = s_new(); 38 mp->size = 0; 39 mp->fd = -1; 40 return mp; 41 } 42 43 extern void 44 m_free(message *mp) 45 { 46 if(mp->fd >= 0){ 47 close(mp->fd); 48 remove(s_to_c(mp->tmp)); 49 s_free(mp->tmp); 50 } 51 s_free(mp->sender); 52 s_free(mp->date); 53 s_free(mp->body); 54 free((char *)mp); 55 } 56 57 /* read a message into a temp file , return an open fd to it */ 58 static int 59 m_read_to_file(Biobuf *fp, message *mp) 60 { 61 int fd; 62 int n; 63 String *file; 64 char buf[4*1024]; 65 66 file = s_new(); 67 /* 68 * create and unlink temp file 69 */ 70 abspath("tmp/mtXXXXXX", MAILROOT, file); 71 mktemp(s_to_c(file)); 72 if((fd = syscreate(s_to_c(file), 0600))<0){ 73 s_free(mp->tmp); 74 return -1; 75 } 76 mp->tmp = file; 77 78 /* 79 * read the rest into the temp file 80 */ 81 while((n = Bread(fp, buf, sizeof(buf))) > 0){ 82 if(write(fd, buf, n) != n){ 83 close(fd); 84 return -1; 85 } 86 mp->size += n; 87 if(mp->size > MSGLIMIT){ 88 mp->size = -1; 89 break; 90 } 91 } 92 93 mp->fd = fd; 94 return 0; 95 } 96 97 /* read in a message, interpret the 'From' header */ 98 extern message * 99 m_read(Biobuf *fp, int rmail) 100 { 101 message *mp; 102 Resub subexp[10]; 103 int first; 104 int n; 105 106 107 mp = m_new(); 108 109 /* parse From lines if remote */ 110 if (rmail) { 111 /* get remote address */ 112 String *sender=s_new(); 113 114 if (rfprog == 0) 115 rfprog = regcomp(REMFROMRE); 116 first = 1; 117 while(s_read_line(fp, s_restart(mp->body)) != 0) { 118 memset(subexp, 0, sizeof(subexp)); 119 if (regexec(rfprog, s_to_c(mp->body), subexp, 10) == 0){ 120 if(first == 0) 121 break; 122 if (fprog == 0) 123 fprog = regcomp(FROMRE); 124 memset(subexp, 0, sizeof(subexp)); 125 if(regexec(fprog, s_to_c(mp->body), subexp,10) == 0) 126 break; 127 USE(s_restart(mp->body)); 128 append_match(subexp, s_restart(sender), SENDERMATCH); 129 append_match(subexp, s_restart(mp->date), DATEMATCH); 130 break; 131 } 132 append_match(subexp, s_restart(sender), REMSENDERMATCH); 133 append_match(subexp, s_restart(mp->date), REMDATEMATCH); 134 if(subexp[REMSYSMATCH].sp!=subexp[REMSYSMATCH].ep){ 135 append_match(subexp, mp->sender, REMSYSMATCH); 136 s_append(mp->sender, "!"); 137 } 138 first = 0; 139 } 140 s_append(mp->sender, s_to_c(sender)); 141 s_free(sender); 142 } 143 if (*s_to_c(mp->sender)=='\0') 144 default_from(mp); 145 146 /* 147 * read up to VMLIMIT bytes (more or less) into main memory. 148 * if message is longer put the rest in a tmp file. 149 */ 150 mp->size = mp->body->ptr - mp->body->base; 151 n = s_read(fp, mp->body, VMLIMIT); 152 if(n < 0){ 153 perror("m_read"); 154 exit(1); 155 } 156 mp->size += n; 157 if(n == VMLIMIT){ 158 if(m_read_to_file(fp, mp) < 0){ 159 perror("m_read"); 160 exit(1); 161 } 162 } 163 164 /* 165 * ignore 0 length messages from a terminal 166 */ 167 if (!rmail && mp->size == 0) 168 return 0; 169 170 return mp; 171 } 172 173 /* return a piece of message starting at `offset' */ 174 extern int 175 m_get(message *mp, long offset, char **pp) 176 { 177 static char buf[4*1024]; 178 179 /* 180 * are we past eof? 181 */ 182 if(offset >= mp->size) 183 return 0; 184 185 /* 186 * are we in the virtual memory portion? 187 */ 188 if(offset < mp->body->ptr - mp->body->base){ 189 *pp = mp->body->base + offset; 190 return mp->body->ptr - mp->body->base - offset; 191 } 192 193 /* 194 * read it from the temp file 195 */ 196 offset -= mp->body->ptr - mp->body->base; 197 if(mp->fd < 0) 198 return -1; 199 if(seek(mp->fd, offset, 0)<0) 200 return -1; 201 *pp = buf; 202 return read(mp->fd, buf, sizeof buf); 203 } 204 205 /* output the message body without ^From escapes */ 206 static int 207 m_noescape(message *mp, Biobuf *fp) 208 { 209 long offset; 210 int n; 211 char *p; 212 213 for(offset = 0; offset < mp->size; offset += n){ 214 n = m_get(mp, offset, &p); 215 if(n <= 0){ 216 Bflush(fp); 217 return -1; 218 } 219 if(Bwrite(fp, p, n) < 0) 220 return -1; 221 } 222 return Bflush(fp); 223 } 224 225 /* 226 * Output the message body with '^From ' escapes. 227 * Ensures that any line starting with a 'From ' gets a ' ' stuck 228 * in front of it. 229 */ 230 static int 231 m_escape(message *mp, Biobuf *fp) 232 { 233 char *p, *np; 234 char *end; 235 long offset; 236 int m, n; 237 char *start; 238 239 for(offset = 0; offset < mp->size; offset += n){ 240 n = m_get(mp, offset, &start); 241 if(n < 0){ 242 Bflush(fp); 243 return -1; 244 } 245 246 p = start; 247 for(end = p+n; p < end; p += m){ 248 np = memchr(p, '\n', end-p); 249 if(np == 0){ 250 Bwrite(fp, p, end-p); 251 break; 252 } 253 m = np - p + 1; 254 if(m > 5 && strncmp(p, "From ", 5) == 0) 255 Bputc(fp, ' '); 256 Bwrite(fp, p, m); 257 } 258 } 259 Bflush(fp); 260 return 0; 261 } 262 263 /* output a message */ 264 extern int 265 m_print(message *mp, Biobuf *fp, char *remote, int mbox) 266 { 267 if (remote != 0){ 268 if(print_remote_header(fp,s_to_c(mp->sender),s_to_c(mp->date),remote) < 0) 269 return -1; 270 } else { 271 if(print_header(fp, s_to_c(mp->sender), s_to_c(mp->date)) < 0) 272 return -1; 273 } 274 275 if (!mbox) 276 return m_noescape(mp, fp); 277 return m_escape(mp, fp); 278 } 279 280 /* print just the message body */ 281 extern int 282 m_bprint(message *mp, Biobuf *fp) 283 { 284 return m_noescape(mp, fp); 285 } 286