1 # 2 3 #include "rcv.h" 4 #include <sys/stat.h> 5 6 /* 7 * Mail -- a mail program 8 * 9 * Still more user commands. 10 */ 11 12 static char *SccsId = "@(#)cmd3.c 1.2 10/08/80"; 13 14 /* 15 * Process a shell escape by saving signals, ignoring signals, 16 * and forking a sh -c 17 */ 18 19 shell(str) 20 char *str; 21 { 22 int (*sig[2])(), stat[1]; 23 register int t; 24 char *Shell; 25 char cmd[BUFSIZ]; 26 27 strcpy(cmd, str); 28 if (bangexp(cmd) < 0) 29 return(-1); 30 if ((Shell = value("SHELL")) == NOSTR) 31 Shell = SHELL; 32 for (t = 2; t < 4; t++) 33 sig[t-2] = signal(t, SIG_IGN); 34 t = vfork(); 35 if (t == 0) { 36 for (t = 2; t < 4; t++) 37 if (sig[t-2] != SIG_IGN) 38 signal(t, SIG_DFL); 39 execl(Shell, Shell, "-c", cmd, 0); 40 perror(Shell); 41 _exit(1); 42 } 43 while (wait(stat) != t) 44 ; 45 if (t == -1) 46 perror("fork"); 47 for (t = 2; t < 4; t++) 48 signal(t, sig[t-2]); 49 printf("!\n"); 50 return(0); 51 } 52 53 /* 54 * Fork an interactive shell. 55 */ 56 57 dosh(str) 58 char *str; 59 { 60 int (*sig[2])(), stat[1]; 61 register int t; 62 char *Shell; 63 if ((Shell = value("SHELL")) == NOSTR) 64 Shell = SHELL; 65 for (t = 2; t < 4; t++) 66 sig[t-2] = signal(t, SIG_IGN); 67 t = vfork(); 68 if (t == 0) { 69 for (t = 2; t < 4; t++) 70 if (sig[t-2] != SIG_IGN) 71 signal(t, SIG_DFL); 72 execl(Shell, Shell, 0); 73 perror(Shell); 74 _exit(1); 75 } 76 while (wait(stat) != t) 77 ; 78 if (t == -1) 79 perror("fork"); 80 for (t = 2; t < 4; t++) 81 signal(t, sig[t-2]); 82 putchar('\n'); 83 return(0); 84 } 85 86 /* 87 * Expand the shell escape by expanding unescaped !'s into the 88 * last issued command where possible. 89 */ 90 91 char lastbang[128]; 92 93 bangexp(str) 94 char *str; 95 { 96 char bangbuf[BUFSIZ]; 97 register char *cp, *cp2; 98 register int n; 99 int changed = 0; 100 101 cp = str; 102 cp2 = bangbuf; 103 n = BUFSIZ; 104 while (*cp) { 105 if (*cp == '!') { 106 if (n < strlen(lastbang)) { 107 overf: 108 printf("Command buffer overflow\n"); 109 return(-1); 110 } 111 changed++; 112 strcpy(cp2, lastbang); 113 cp2 += strlen(lastbang); 114 n -= strlen(lastbang); 115 cp++; 116 continue; 117 } 118 if (*cp == '\\' && cp[1] == '!') { 119 if (--n <= 1) 120 goto overf; 121 *cp2++ = '!'; 122 cp += 2; 123 changed++; 124 } 125 if (--n <= 1) 126 goto overf; 127 *cp2++ = *cp++; 128 } 129 *cp2 = 0; 130 if (changed) { 131 printf("!%s\n", bangbuf); 132 fflush(stdout); 133 } 134 strcpy(str, bangbuf); 135 strncpy(lastbang, bangbuf, 128); 136 lastbang[127] = 0; 137 return(0); 138 } 139 140 /* 141 * Print out a nice help message from some file or another. 142 */ 143 144 help() 145 { 146 register c; 147 register FILE *f; 148 149 if ((f = fopen(HELPFILE, "r")) == NULL) { 150 printf("No help just now.\n"); 151 return(1); 152 } 153 while ((c = getc(f)) != EOF) 154 putchar(c); 155 fclose(f); 156 return(0); 157 } 158 159 /* 160 * Change user's working directory. 161 */ 162 163 schdir(str) 164 char *str; 165 { 166 register char *cp; 167 168 for (cp = str; *cp == ' '; cp++) 169 ; 170 if (*cp == '\0') 171 cp = homedir; 172 else 173 if ((cp = expand(cp)) == NOSTR) 174 return(1); 175 if (chdir(cp) < 0) { 176 perror(cp); 177 return(1); 178 } 179 return(0); 180 } 181 182 /* 183 * Reply to a list of messages. Extract each name from the 184 * message header and send them off to mail1() 185 */ 186 187 respond(msgvec) 188 int *msgvec; 189 { 190 struct message *mp; 191 char *cp, buf[2 * LINESIZE], *rcv; 192 struct name *np; 193 struct header head; 194 char *netmap(); 195 196 if (msgvec[1] != 0) { 197 printf("Sorry, can't reply to multiple messages at once\n"); 198 return(1); 199 } 200 mp = &message[msgvec[0] - 1]; 201 dot = mp; 202 rcv = nameof(mp); 203 strcpy(buf, ""); 204 cp = hfield("to", mp); 205 if (cp != NOSTR) 206 strcpy(buf, cp); 207 np = elide(extract(buf, GTO)); 208 /* rcv = rename(rcv); */ 209 mapf(np, rcv); 210 np = delname(np, myname); 211 head.h_seq = 1; 212 cp = detract(np, 0); 213 if (cp != NOSTR) { 214 strcpy(buf, cp); 215 strcat(buf, " "); 216 strcat(buf, rcv); 217 } 218 else 219 strcpy(buf, rcv); 220 head.h_to = buf; 221 head.h_subject = hfield("subject", mp); 222 if (head.h_subject == NOSTR) 223 head.h_subject = hfield("subj", mp); 224 head.h_cc = NOSTR; 225 cp = hfield("cc", mp); 226 if (cp != NOSTR) { 227 np = elide(extract(cp, GCC)); 228 mapf(np, rcv); 229 np = delname(np, myname); 230 head.h_cc = detract(np, 0); 231 } 232 head.h_bcc = NOSTR; 233 mail1(&head); 234 return(0); 235 } 236 237 /* 238 * Preserve the named messages, so that they will be sent 239 * back to the system mailbox. 240 */ 241 242 preserve(msgvec) 243 int *msgvec; 244 { 245 register struct message *mp; 246 register int *ip, mesg; 247 248 if (edit) { 249 printf("Cannot \"preserve\" in edit mode\n"); 250 return(1); 251 } 252 for (ip = msgvec; *ip != NULL; ip++) { 253 mesg = *ip; 254 mp = &message[mesg-1]; 255 mp->m_flag |= MPRESERVE; 256 dot = mp; 257 } 258 return(0); 259 } 260 261 /* 262 * Print the size of each message. 263 */ 264 265 messize(msgvec) 266 int *msgvec; 267 { 268 register struct message *mp; 269 register int *ip, mesg; 270 271 for (ip = msgvec; *ip != NULL; ip++) { 272 mesg = *ip; 273 mp = &message[mesg-1]; 274 printf("%d: %d\n", mesg, msize(mp)); 275 } 276 return(0); 277 } 278 279 /* 280 * Quit quickly. If we are sourcing, just pop the input level 281 * by returning an error. 282 */ 283 284 rexit(e) 285 { 286 if (sourcing) 287 return(1); 288 exit(e); 289 } 290 291 /* 292 * Set or display a variable value. Syntax is similar to that 293 * of csh. 294 */ 295 296 set(arglist) 297 char **arglist; 298 { 299 register struct var *vp; 300 register char *cp, *cp2; 301 char varbuf[BUFSIZ], **ap, **p; 302 int errs, h, s; 303 304 if (argcount(arglist) == 0) { 305 for (h = 0, s = 1; h < HSHSIZE; h++) 306 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) 307 s++; 308 ap = (char **) salloc(s * sizeof *ap); 309 for (h = 0, p = ap; h < HSHSIZE; h++) 310 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) 311 *p++ = vp->v_name; 312 *p = NOSTR; 313 sort(ap); 314 for (p = ap; *p != NOSTR; p++) 315 printf("%s\t%s\n", *p, value(*p)); 316 return(0); 317 } 318 errs = 0; 319 for (ap = arglist; *ap != NOSTR; ap++) { 320 cp = *ap; 321 cp2 = varbuf; 322 while (*cp != '=' && *cp != '\0') 323 *cp2++ = *cp++; 324 *cp2 = '\0'; 325 if (*cp == '\0') 326 cp = ""; 327 else 328 cp++; 329 if (equal(varbuf, "")) { 330 printf("Non-null variable name required\n"); 331 errs++; 332 continue; 333 } 334 assign(varbuf, cp); 335 } 336 return(errs); 337 } 338 339 /* 340 * Unset a bunch of variable values. 341 */ 342 343 unset(arglist) 344 char **arglist; 345 { 346 register struct var *vp, *vp2; 347 register char *cp; 348 int errs, h; 349 char **ap; 350 351 errs = 0; 352 for (ap = arglist; *ap != NOSTR; ap++) { 353 if ((vp2 = lookup(*ap)) == NOVAR) { 354 if (!sourcing) { 355 printf("\"%s\": undefined variable\n", *ap); 356 errs++; 357 } 358 continue; 359 } 360 h = hash(*ap); 361 if (vp2 == variables[h]) { 362 variables[h] = variables[h]->v_link; 363 vfree(vp2->v_name); 364 vfree(vp2->v_value); 365 cfree(vp2); 366 continue; 367 } 368 for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link) 369 ; 370 vp->v_link = vp2->v_link; 371 vfree(vp2->v_name); 372 vfree(vp2->v_value); 373 cfree(vp2); 374 } 375 return(errs); 376 } 377 378 /* 379 * Put add users to a group. 380 */ 381 382 group(argv) 383 char **argv; 384 { 385 register struct grouphead *gh; 386 register struct group *gp; 387 register int h; 388 int s; 389 char **ap, *gname, **p; 390 391 if (argcount(argv) == 0) { 392 for (h = 0, s = 1; h < HSHSIZE; h++) 393 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) 394 s++; 395 ap = (char **) salloc(s * sizeof *ap); 396 for (h = 0, p = ap; h < HSHSIZE; h++) 397 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) 398 *p++ = gh->g_name; 399 *p = NOSTR; 400 sort(ap); 401 for (p = ap; *p != NOSTR; p++) 402 printgroup(*p); 403 return(0); 404 } 405 if (argcount(argv) == 1) { 406 printgroup(*argv); 407 return(0); 408 } 409 gname = *argv; 410 h = hash(gname); 411 if ((gh = findgroup(gname)) == NOGRP) { 412 gh = (struct grouphead *) calloc(sizeof *gh, 1); 413 gh->g_name = vcopy(gname); 414 gh->g_list = NOGE; 415 gh->g_link = groups[h]; 416 groups[h] = gh; 417 } 418 419 /* 420 * Insert names from the command list into the group. 421 * Who cares if there are duplicates? They get tossed 422 * later anyway. 423 */ 424 425 for (ap = argv+1; *ap != NOSTR; ap++) { 426 gp = (struct group *) calloc(sizeof *gp, 1); 427 gp->ge_name = vcopy(*ap); 428 gp->ge_link = gh->g_list; 429 gh->g_list = gp; 430 } 431 return(0); 432 } 433 434 /* 435 * Sort the passed string vecotor into ascending dictionary 436 * order. 437 */ 438 439 sort(list) 440 char **list; 441 { 442 register char **ap; 443 int diction(); 444 445 for (ap = list; *ap != NOSTR; ap++) 446 ; 447 if (ap-list < 2) 448 return; 449 qsort(list, ap-list, sizeof *list, diction); 450 } 451 452 /* 453 * Do a dictionary order comparison of the arguments from 454 * qsort. 455 */ 456 457 diction(a, b) 458 register char **a, **b; 459 { 460 return(strcmp(*a, *b)); 461 } 462 463 /* 464 * The do nothing command for comments. 465 */ 466 467 null(e) 468 { 469 return(0); 470 } 471 472 /* 473 * Print out the current edit file, if we are editting. 474 * Otherwise, print the name of the person who's mail 475 * we are reading. 476 */ 477 478 file(e) 479 { 480 register char *cp; 481 482 if (edit) 483 printf("Reading \"%s\"\n", editfile); 484 else 485 printf("Reading %s's mail\n", rindex(mailname, '/') + 1); 486 return(0); 487 } 488 489 /* 490 * Expand file names like echo 491 */ 492 493 echo(argv) 494 char **argv; 495 { 496 register char **ap; 497 register char *cp; 498 499 for (ap = argv; *ap != NOSTR; ap++) { 500 cp = *ap; 501 if ((cp = expand(cp)) != NOSTR) 502 printf("%s\n", cp); 503 } 504 return(0); 505 } 506 507 /* 508 * Reply to a series of messages by simply mailing to the senders 509 * and not messing around with the To: and Cc: lists as in normal 510 * reply. 511 */ 512 513 Respond(msgvec) 514 int msgvec[]; 515 { 516 struct header head; 517 struct message *mp; 518 register int s, *ap; 519 register char *cp, *subject; 520 521 for (s = 0, ap = msgvec; *ap != 0; ap++) { 522 mp = &message[*ap - 1]; 523 dot = mp; 524 s += strlen(nameof(mp)) + 1; 525 } 526 if (s == 0) 527 return(0); 528 cp = salloc(s + 2); 529 head.h_to = cp; 530 for (ap = msgvec; *ap != 0; ap++) { 531 mp = &message[*ap - 1]; 532 cp = copy(nameof(mp), cp); 533 *cp++ = ' '; 534 } 535 *--cp = 0; 536 mp = &message[msgvec[0] - 1]; 537 subject = hfield("subject", mp); 538 head.h_seq = 0; 539 if (subject == NOSTR) 540 subject = hfield("subj", mp); 541 head.h_subject = subject; 542 if (subject != NOSTR) 543 head.h_seq++; 544 head.h_cc = NOSTR; 545 head.h_bcc = NOSTR; 546 mail1(&head); 547 return(0); 548 } 549