1 # 2 3 #include "rcv.h" 4 #include <sys/stat.h> 5 6 /* 7 * Mail -- a mail program 8 * 9 * More user commands. 10 */ 11 12 static char *SccsId = "@(#)cmd2.c 2.4 02/13/82"; 13 14 /* 15 * If any arguments were given, go to the next applicable argument 16 * following dot, otherwise, go to the next applicable message. 17 * If given as first command with no arguments, print first message. 18 */ 19 20 next(msgvec) 21 int *msgvec; 22 { 23 register struct message *mp; 24 register int *ip, *ip2; 25 int list[2], mdot; 26 27 if (*msgvec != NULL) { 28 29 /* 30 * If some messages were supplied, find the 31 * first applicable one following dot using 32 * wrap around. 33 */ 34 35 mdot = dot - &message[0] + 1; 36 37 /* 38 * Find the first message in the supplied 39 * message list which follows dot. 40 */ 41 42 for (ip = msgvec; *ip != NULL; ip++) 43 if (*ip > mdot) 44 break; 45 if (*ip == NULL) 46 ip = msgvec; 47 ip2 = ip; 48 do { 49 mp = &message[*ip2 - 1]; 50 if ((mp->m_flag & MDELETED) == 0) { 51 dot = mp; 52 goto hitit; 53 } 54 if (*ip2 != NULL) 55 ip2++; 56 if (*ip2 == NULL) 57 ip2 = msgvec; 58 } while (ip2 != ip); 59 printf("No messages applicable\n"); 60 return(1); 61 } 62 63 /* 64 * If this is the first command, select message 1. 65 * Note that this must exist for us to get here at all. 66 */ 67 68 if (!sawcom) 69 goto hitit; 70 71 /* 72 * Just find the next good message after dot, no 73 * wraparound. 74 */ 75 76 for (mp = dot+1; mp < &message[msgCount]; mp++) 77 if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 78 break; 79 if (mp >= &message[msgCount]) { 80 printf("At EOF\n"); 81 return(0); 82 } 83 dot = mp; 84 hitit: 85 /* 86 * Print dot. 87 */ 88 89 list[0] = dot - &message[0] + 1; 90 list[1] = NULL; 91 return(type(list)); 92 } 93 94 /* 95 * Save a message in a file. Mark the message as saved 96 * so we can discard when the user quits. 97 */ 98 save(str) 99 char str[]; 100 { 101 102 return(save1(str, 1)); 103 } 104 105 /* 106 * Copy a message to a file without affected its saved-ness 107 */ 108 copycmd(str) 109 char str[]; 110 { 111 112 return(save1(str, 0)); 113 } 114 115 /* 116 * Save/copy the indicated messages at the end of the passed file name. 117 * If mark is true, mark the message "saved." 118 */ 119 save1(str, mark) 120 char str[]; 121 { 122 register int *ip, mesg; 123 register struct message *mp; 124 char *file, *disp, *cmd; 125 int f, *msgvec, lc, cc, t; 126 FILE *obuf; 127 struct stat statb; 128 129 cmd = mark ? "save" : "copy"; 130 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 131 if ((file = snarf(str, &f)) == NOSTR) 132 return(1); 133 if (!f) { 134 *msgvec = first(0, MMNORM); 135 if (*msgvec == NULL) { 136 printf("No messages to %s.\n", cmd); 137 return(1); 138 } 139 msgvec[1] = NULL; 140 } 141 if (f && getmsglist(str, msgvec, 0) < 0) 142 return(1); 143 if ((file = expand(file)) == NOSTR) 144 return(1); 145 printf("\"%s\" ", file); 146 flush(); 147 if (stat(file, &statb) >= 0) 148 disp = "[Appended]"; 149 else 150 disp = "[New file]"; 151 if ((obuf = fopen(file, "a")) == NULL) { 152 perror(NOSTR); 153 return(1); 154 } 155 cc = lc = 0; 156 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 157 mesg = *ip; 158 touch(mesg); 159 mp = &message[mesg-1]; 160 if ((t = send(mp, obuf)) < 0) { 161 perror(file); 162 fclose(obuf); 163 return(1); 164 } 165 lc += t; 166 cc += msize(mp); 167 if (mark) 168 mp->m_flag |= MSAVED; 169 } 170 fflush(obuf); 171 if (ferror(obuf)) 172 perror(file); 173 fclose(obuf); 174 printf("%s %d/%d\n", disp, lc, cc); 175 return(0); 176 } 177 178 /* 179 * Write the indicated messages at the end of the passed 180 * file name, minus header and trailing blank line. 181 */ 182 183 swrite(str) 184 char str[]; 185 { 186 register int *ip, mesg; 187 register struct message *mp; 188 register char *file, *disp; 189 char linebuf[BUFSIZ]; 190 int f, *msgvec, lc, cc, t; 191 FILE *obuf, *mesf; 192 struct stat statb; 193 194 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 195 if ((file = snarf(str, &f)) == NOSTR) 196 return(1); 197 if ((file = expand(file)) == NOSTR) 198 return(1); 199 if (!f) { 200 *msgvec = first(0, MMNORM); 201 if (*msgvec == NULL) { 202 printf("No messages to write.\n"); 203 return(1); 204 } 205 msgvec[1] = NULL; 206 } 207 if (f && getmsglist(str, msgvec, 0) < 0) 208 return(1); 209 printf("\"%s\" ", file); 210 flush(); 211 if (stat(file, &statb) >= 0) 212 disp = "[Appended]"; 213 else 214 disp = "[New file]"; 215 if ((obuf = fopen(file, "a")) == NULL) { 216 perror(NOSTR); 217 return(1); 218 } 219 cc = lc = 0; 220 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 221 mesg = *ip; 222 touch(mesg); 223 mp = &message[mesg-1]; 224 mesf = setinput(mp); 225 t = mp->m_lines - 2; 226 readline(mesf, linebuf); 227 while (t-- > 0) { 228 fgets(linebuf, BUFSIZ, mesf); 229 fputs(linebuf, obuf); 230 cc += strlen(linebuf); 231 } 232 lc += mp->m_lines - 2; 233 mp->m_flag |= MSAVED; 234 } 235 fflush(obuf); 236 if (ferror(obuf)) 237 perror(file); 238 fclose(obuf); 239 printf("%s %d/%d\n", disp, lc, cc); 240 return(0); 241 } 242 243 /* 244 * Snarf the file from the end of the command line and 245 * return a pointer to it. If there is no file attached, 246 * just return NOSTR. Put a null in front of the file 247 * name so that the message list processing won't see it, 248 * unless the file name is the only thing on the line, in 249 * which case, return 0 in the reference flag variable. 250 */ 251 252 char * 253 snarf(linebuf, flag) 254 char linebuf[]; 255 int *flag; 256 { 257 register char *cp; 258 259 *flag = 1; 260 cp = strlen(linebuf) + linebuf - 1; 261 262 /* 263 * Strip away trailing blanks. 264 */ 265 266 while (*cp == ' ' && cp > linebuf) 267 cp--; 268 *++cp = 0; 269 270 /* 271 * Now search for the beginning of the file name. 272 */ 273 274 while (cp > linebuf && !any(*cp, "\t ")) 275 cp--; 276 if (*cp == '\0') { 277 printf("No file specified.\n"); 278 return(NOSTR); 279 } 280 if (any(*cp, " \t")) 281 *cp++ = 0; 282 else 283 *flag = 0; 284 return(cp); 285 } 286 287 /* 288 * Delete messages. 289 */ 290 291 delete(msgvec) 292 int msgvec[]; 293 { 294 return(delm(msgvec)); 295 } 296 297 /* 298 * Delete messages, then type the new dot. 299 */ 300 301 deltype(msgvec) 302 int msgvec[]; 303 { 304 int list[2]; 305 int lastdot; 306 307 lastdot = dot - &message[0] + 1; 308 if (delm(msgvec) >= 0) { 309 list[0] = dot - &message[0]; 310 list[0]++; 311 if (list[0] > lastdot) { 312 touch(list[0]); 313 list[1] = NULL; 314 return(type(list)); 315 } 316 printf("At EOF\n"); 317 return(0); 318 } 319 else { 320 printf("No more messages\n"); 321 return(0); 322 } 323 } 324 325 /* 326 * Delete the indicated messages. 327 * Set dot to some nice place afterwards. 328 * Internal interface. 329 */ 330 331 delm(msgvec) 332 int *msgvec; 333 { 334 register struct message *mp; 335 register *ip, mesg; 336 int last; 337 338 last = NULL; 339 for (ip = msgvec; *ip != NULL; ip++) { 340 mesg = *ip; 341 touch(mesg); 342 mp = &message[mesg-1]; 343 mp->m_flag |= MDELETED|MTOUCH; 344 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 345 last = mesg; 346 } 347 if (last != NULL) { 348 dot = &message[last-1]; 349 last = first(0, MDELETED); 350 if (last != NULL) { 351 dot = &message[last-1]; 352 return(0); 353 } 354 else { 355 dot = &message[0]; 356 return(-1); 357 } 358 } 359 360 /* 361 * Following can't happen -- it keeps lint happy 362 */ 363 364 return(-1); 365 } 366 367 /* 368 * Undelete the indicated messages. 369 */ 370 371 undelete(msgvec) 372 int *msgvec; 373 { 374 register struct message *mp; 375 register *ip, mesg; 376 377 for (ip = msgvec; ip-msgvec < msgCount; ip++) { 378 mesg = *ip; 379 if (mesg == 0) 380 return; 381 touch(mesg); 382 mp = &message[mesg-1]; 383 dot = mp; 384 mp->m_flag &= ~MDELETED; 385 } 386 } 387 388 /* 389 * Interactively dump core on "core" 390 */ 391 392 core() 393 { 394 register int pid; 395 int status; 396 397 if ((pid = vfork()) == -1) { 398 perror("fork"); 399 return(1); 400 } 401 if (pid == 0) { 402 abort(); 403 _exit(1); 404 } 405 printf("Okie dokie"); 406 fflush(stdout); 407 while (wait(&status) != pid) 408 ; 409 if (status & 0200) 410 printf(" -- Core dumped\n"); 411 else 412 printf("\n"); 413 } 414 415 /* 416 * Clobber as many bytes of stack as the user requests. 417 */ 418 clobber(argv) 419 char **argv; 420 { 421 register int times; 422 423 if (argv[0] == 0) 424 times = 1; 425 else 426 times = (atoi(argv[0]) + 511) / 512; 427 clobber1(times); 428 } 429 430 /* 431 * Clobber the stack. 432 */ 433 clobber1(n) 434 { 435 char buf[512]; 436 register char *cp; 437 438 if (n <= 0) 439 return; 440 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 441 ; 442 clobber1(n - 1); 443 } 444