|
|
1.1 ! root 1: /* sendmail-like interface to /bin/mail for system V, ! 2: Copyright (C) 1985 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #define NO_SHORTNAMES ! 23: #include "../src/config.h" ! 24: ! 25: #if defined (BSD) && !defined (BSD4_1) ! 26: /* This program isnot used in BSD, so just avoid loader complaints. */ ! 27: main () ! 28: { ! 29: } ! 30: #else /* not BSD 4.2 (or newer) */ ! 31: /* This conditional contains all the rest of the file. */ ! 32: ! 33: /* These are defined in config in some versions. */ ! 34: ! 35: #ifdef static ! 36: #undef static ! 37: #endif ! 38: ! 39: #ifdef read ! 40: #undef read ! 41: #undef write ! 42: #undef open ! 43: #endif ! 44: ! 45: #include <stdio.h> ! 46: #include <string.h> ! 47: #include <ctype.h> ! 48: #include <time.h> ! 49: #include <pwd.h> ! 50: ! 51: /* Type definitions */ ! 52: ! 53: #define boolean int ! 54: #define true 1 ! 55: #define false 0 ! 56: ! 57: /* Various lists */ ! 58: ! 59: struct line_record ! 60: { ! 61: char *string; ! 62: struct line_record *continuation; ! 63: }; ! 64: typedef struct line_record *line_list; ! 65: ! 66: struct header_record ! 67: { ! 68: line_list text; ! 69: struct header_record *next; ! 70: struct header_record *previous; ! 71: }; ! 72: typedef struct header_record *header; ! 73: ! 74: struct stream_record ! 75: { ! 76: FILE *handle; ! 77: int (*action)(); ! 78: struct stream_record *rest_streams; ! 79: }; ! 80: typedef struct stream_record *stream_list; ! 81: ! 82: /* A `struct linebuffer' is a structure which holds a line of text. ! 83: * `readline' reads a line from a stream into a linebuffer ! 84: * and works regardless of the length of the line. ! 85: */ ! 86: ! 87: struct linebuffer ! 88: { ! 89: long size; ! 90: char *buffer; ! 91: }; ! 92: ! 93: struct linebuffer lb; ! 94: ! 95: #define new_list() \ ! 96: ((line_list) xmalloc (sizeof (struct line_record))) ! 97: #define new_header() \ ! 98: ((header) xmalloc (sizeof (struct header_record))) ! 99: #define new_stream() \ ! 100: ((stream_list) xmalloc (sizeof (struct stream_record))) ! 101: #define alloc_string(nchars) \ ! 102: ((char *) xmalloc ((nchars) + 1)) ! 103: ! 104: /* Global declarations */ ! 105: ! 106: #define BUFLEN 1024 ! 107: #define KEYWORD_SIZE 256 ! 108: #define PROGRAM_NAME "/bin/mail" ! 109: #define FROM_PREFIX "From" ! 110: #define MY_NAME "fakemail" ! 111: #define NIL ((line_list) NULL) ! 112: #define INITIAL_LINE_SIZE 200 ! 113: ! 114: static char *my_name; ! 115: static char *the_date; ! 116: static char *the_user; ! 117: static line_list file_preface; ! 118: static stream_list the_streams; ! 119: static boolean no_problems = true; ! 120: ! 121: extern FILE *popen (); ! 122: extern int fclose (), pclose (); ! 123: extern char *malloc (), *realloc (); ! 124: ! 125: #ifdef CURRENT_USER ! 126: extern struct passwd *getpwuid (); ! 127: extern unsigned short geteuid (); ! 128: static struct passwd *my_entry; ! 129: #define cuserid(s) \ ! 130: (my_entry = getpwuid (((int) geteuid ())), \ ! 131: my_entry->pw_name) ! 132: #endif ! 133: ! 134: /* Utilities */ ! 135: ! 136: /* Print error message. `s1' is printf control string, `s2' is arg for it. */ ! 137: ! 138: static void ! 139: error (s1, s2) ! 140: char *s1, *s2; ! 141: { ! 142: printf ("%s: ", my_name); ! 143: printf (s1, s2); ! 144: printf ("\n"); ! 145: no_problems = false; ! 146: } ! 147: ! 148: /* Print error message and exit. */ ! 149: ! 150: static void ! 151: fatal (s1, s2) ! 152: char *s1, *s2; ! 153: { ! 154: error (s1, s2); ! 155: exit (1); ! 156: } ! 157: ! 158: /* Like malloc but get fatal error if memory is exhausted. */ ! 159: ! 160: static char * ! 161: xmalloc (size) ! 162: int size; ! 163: { ! 164: char *result = malloc (((unsigned) size)); ! 165: if (result == ((char *) NULL)) ! 166: fatal ("virtual memory exhausted", 0); ! 167: return result; ! 168: } ! 169: ! 170: static char * ! 171: xrealloc (ptr, size) ! 172: char *ptr; ! 173: int size; ! 174: { ! 175: char *result = realloc (ptr, ((unsigned) size)); ! 176: if (result == ((char *) NULL)) ! 177: fatal ("virtual memory exhausted"); ! 178: return result; ! 179: } ! 180: ! 181: /* Initialize a linebuffer for use */ ! 182: ! 183: void ! 184: init_linebuffer (linebuffer) ! 185: struct linebuffer *linebuffer; ! 186: { ! 187: linebuffer->size = INITIAL_LINE_SIZE; ! 188: linebuffer->buffer = ((char *) xmalloc (INITIAL_LINE_SIZE)); ! 189: } ! 190: ! 191: /* Read a line of text from `stream' into `linebuffer'. ! 192: * Return the length of the line. ! 193: */ ! 194: ! 195: long ! 196: readline (linebuffer, stream) ! 197: struct linebuffer *linebuffer; ! 198: FILE *stream; ! 199: { ! 200: char *buffer = linebuffer->buffer; ! 201: char *p = linebuffer->buffer; ! 202: char *end = p + linebuffer->size; ! 203: ! 204: while (true) ! 205: { ! 206: int c = getc (stream); ! 207: if (p == end) ! 208: { ! 209: linebuffer->size *= 2; ! 210: buffer = ((char *) xrealloc (buffer, linebuffer->size)); ! 211: p += buffer - linebuffer->buffer; ! 212: end += buffer - linebuffer->buffer; ! 213: linebuffer->buffer = buffer; ! 214: } ! 215: if (c < 0 || c == '\n') ! 216: { ! 217: *p = 0; ! 218: break; ! 219: } ! 220: *p++ = c; ! 221: } ! 222: ! 223: return p - buffer; ! 224: } ! 225: ! 226: char * ! 227: get_keyword (field, rest) ! 228: register char *field; ! 229: char **rest; ! 230: { ! 231: static char keyword[KEYWORD_SIZE]; ! 232: register char *ptr; ! 233: register char c; ! 234: ! 235: ptr = &keyword[0]; ! 236: c = *field++; ! 237: if ((isspace (c)) || (c == ':')) ! 238: return ((char *) NULL); ! 239: *ptr++ = ((islower (c)) ? (toupper (c)) : c); ! 240: while (((c = *field++) != ':') && (!(isspace (c)))) ! 241: *ptr++ = ((islower (c)) ? (toupper (c)) : c); ! 242: *ptr++ = '\0'; ! 243: while (isspace (c)) c = *field++; ! 244: if (c != ':') return ((char *) NULL); ! 245: *rest = field; ! 246: return &keyword[0]; ! 247: } ! 248: ! 249: boolean ! 250: has_keyword (field) ! 251: char *field; ! 252: { ! 253: char *ignored; ! 254: return (get_keyword (field, &ignored) != ((char *) NULL)); ! 255: } ! 256: ! 257: char * ! 258: add_field (the_list, field, where) ! 259: line_list the_list; ! 260: register char *field, *where; ! 261: { ! 262: register char c; ! 263: while (true) ! 264: { ! 265: *where++ = ' '; ! 266: while ((c = *field++) != '\0') ! 267: *where++ = ((c == ',') ? ' ' : c); ! 268: if (the_list == NIL) break; ! 269: field = the_list->string; ! 270: the_list = the_list->continuation; ! 271: } ! 272: return where; ! 273: } ! 274: ! 275: line_list ! 276: make_file_preface () ! 277: { ! 278: char *the_string, *temp; ! 279: long idiotic_interface; ! 280: long prefix_length; ! 281: long user_length; ! 282: long date_length; ! 283: line_list result; ! 284: ! 285: prefix_length = strlen (FROM_PREFIX); ! 286: time (&idiotic_interface); ! 287: the_date = ctime (&idiotic_interface); ! 288: /* the_date has an unwanted newline at the end */ ! 289: date_length = strlen (the_date) - 1; ! 290: the_date[date_length] = '\0'; ! 291: temp = cuserid ((char *) NULL); ! 292: user_length = strlen (temp); ! 293: the_user = alloc_string (user_length + 1); ! 294: strcpy (the_user, temp); ! 295: the_string = alloc_string (3 + prefix_length + ! 296: user_length + ! 297: date_length); ! 298: temp = the_string; ! 299: strcpy (temp, FROM_PREFIX); ! 300: temp = &temp[prefix_length]; ! 301: *temp++ = ' '; ! 302: strcpy (temp, the_user); ! 303: temp = &temp[user_length]; ! 304: *temp++ = ' '; ! 305: strcpy (temp, the_date); ! 306: result = new_list (); ! 307: result->string = the_string; ! 308: result->continuation = ((line_list) NULL); ! 309: return result; ! 310: } ! 311: ! 312: void ! 313: write_line_list (the_list, the_stream) ! 314: register line_list the_list; ! 315: FILE *the_stream; ! 316: { ! 317: for ( ; ! 318: the_list != ((line_list) NULL) ; ! 319: the_list = the_list->continuation) ! 320: { ! 321: fputs (the_list->string, the_stream); ! 322: putc ('\n', the_stream); ! 323: } ! 324: return; ! 325: } ! 326: ! 327: int ! 328: close_the_streams () ! 329: { ! 330: register stream_list rem; ! 331: for (rem = the_streams; ! 332: rem != ((stream_list) NULL); ! 333: rem = rem->rest_streams) ! 334: no_problems = (no_problems && ! 335: (rem->action (rem->handle) == 0)); ! 336: the_streams = ((stream_list) NULL); ! 337: return (no_problems ? 0 : 1); ! 338: } ! 339: ! 340: void ! 341: add_a_stream (the_stream, closing_action) ! 342: FILE *the_stream; ! 343: int (*closing_action)(); ! 344: { ! 345: stream_list old = the_streams; ! 346: the_streams = new_stream (); ! 347: the_streams->handle = the_stream; ! 348: the_streams->action = closing_action; ! 349: the_streams->rest_streams = old; ! 350: return; ! 351: } ! 352: ! 353: int ! 354: my_fclose (the_file) ! 355: FILE *the_file; ! 356: { ! 357: putc ('\n', the_file); ! 358: fflush (the_file); ! 359: return fclose (the_file); ! 360: } ! 361: ! 362: boolean ! 363: open_a_file (name) ! 364: char *name; ! 365: { ! 366: FILE *the_stream = fopen (name, "a"); ! 367: if (the_stream != ((FILE *) NULL)) ! 368: { ! 369: add_a_stream (the_stream, my_fclose); ! 370: if (the_user == ((char *) NULL)) ! 371: file_preface = make_file_preface (); ! 372: write_line_list (file_preface, the_stream); ! 373: return true; ! 374: } ! 375: return false; ! 376: } ! 377: ! 378: void ! 379: put_string (s) ! 380: char *s; ! 381: { ! 382: register stream_list rem; ! 383: for (rem = the_streams; ! 384: rem != ((stream_list) NULL); ! 385: rem = rem->rest_streams) ! 386: fputs (s, rem->handle); ! 387: return; ! 388: } ! 389: ! 390: void ! 391: put_line (s) ! 392: char *s; ! 393: { ! 394: register stream_list rem; ! 395: for (rem = the_streams; ! 396: rem != ((stream_list) NULL); ! 397: rem = rem->rest_streams) ! 398: { ! 399: fputs (s, rem->handle); ! 400: putc ('\n', rem->handle); ! 401: } ! 402: return; ! 403: } ! 404: ! 405: #define mail_error error ! 406: ! 407: void ! 408: setup_files (the_list, field) ! 409: register line_list the_list; ! 410: register char *field; ! 411: { ! 412: register char *start; ! 413: register char c; ! 414: while (true) ! 415: { ! 416: while (((c = *field) != '\0') && ! 417: ((c == ' ') || ! 418: (c == '\t') || ! 419: (c == ','))) ! 420: field += 1; ! 421: if (c != '\0') ! 422: { ! 423: start = field; ! 424: while (((c = *field) != '\0') && ! 425: (c != ' ') && ! 426: (c != '\t') && ! 427: (c != ',')) ! 428: field += 1; ! 429: *field = '\0'; ! 430: if (!open_a_file (start)) ! 431: mail_error ("Could not open file %s", start); ! 432: *field = c; ! 433: if (c != '\0') continue; ! 434: } ! 435: if (the_list == ((line_list) NULL)) return; ! 436: field = the_list->string; ! 437: the_list = the_list->continuation; ! 438: } ! 439: } ! 440: ! 441: int ! 442: args_size (the_header) ! 443: header the_header; ! 444: { ! 445: register header old = the_header; ! 446: register line_list rem; ! 447: register int size = 0; ! 448: do ! 449: { ! 450: char *field; ! 451: register char *keyword = get_keyword (the_header->text->string, &field); ! 452: if ((strcmp (keyword, "TO") == 0) || ! 453: (strcmp (keyword, "CC") == 0) || ! 454: (strcmp (keyword, "BCC") == 0)) ! 455: { ! 456: size += 1 + strlen (field); ! 457: for (rem = the_header->text->continuation; ! 458: rem != NIL; ! 459: rem = rem->continuation) ! 460: size += 1 + strlen (rem->string); ! 461: } ! 462: the_header = the_header->next; ! 463: } while (the_header != old); ! 464: return size; ! 465: } ! 466: ! 467: parse_header (the_header, where) ! 468: header the_header; ! 469: register char *where; ! 470: { ! 471: register header old = the_header; ! 472: do ! 473: { ! 474: char *field; ! 475: register char *keyword = get_keyword (the_header->text->string, &field); ! 476: if (strcmp (keyword, "TO") == 0) ! 477: where = add_field (the_header->text->continuation, field, where); ! 478: else if (strcmp (keyword, "CC") == 0) ! 479: where = add_field (the_header->text->continuation, field, where); ! 480: else if (strcmp (keyword, "BCC") == 0) ! 481: { ! 482: where = add_field (the_header->text->continuation, field, where); ! 483: the_header->previous->next = the_header->next; ! 484: the_header->next->previous = the_header->previous; ! 485: } ! 486: else if (strcmp (keyword, "FCC") == 0) ! 487: setup_files (the_header->text->continuation, field); ! 488: the_header = the_header->next; ! 489: } while (the_header != old); ! 490: *where = '\0'; ! 491: return; ! 492: } ! 493: ! 494: header ! 495: read_header () ! 496: { ! 497: register header the_header = ((header) NULL); ! 498: register line_list *next_line = ((line_list *) NULL); ! 499: ! 500: init_linebuffer (&lb); ! 501: ! 502: do ! 503: { ! 504: long length; ! 505: register char *line; ! 506: ! 507: readline (&lb, stdin); ! 508: line = lb.buffer; ! 509: length = strlen (line); ! 510: if (length == 0) break; ! 511: ! 512: if (has_keyword (line)) ! 513: { ! 514: register header old = the_header; ! 515: the_header = new_header (); ! 516: if (old == ((header) NULL)) ! 517: { ! 518: the_header->next = the_header; ! 519: the_header->previous = the_header; ! 520: } ! 521: else ! 522: { ! 523: the_header->previous = old; ! 524: the_header->next = old->next; ! 525: old->next = the_header; ! 526: } ! 527: next_line = &(the_header->text); ! 528: } ! 529: ! 530: if (next_line == ((line_list *) NULL)) ! 531: { ! 532: /* Not a valid header */ ! 533: exit (1); ! 534: } ! 535: *next_line = new_list (); ! 536: (*next_line)->string = alloc_string (length); ! 537: strcpy (((*next_line)->string), line); ! 538: next_line = &((*next_line)->continuation); ! 539: *next_line = NIL; ! 540: ! 541: } while (true); ! 542: ! 543: return the_header->next; ! 544: } ! 545: ! 546: void ! 547: write_header (the_header) ! 548: header the_header; ! 549: { ! 550: register header old = the_header; ! 551: do ! 552: { ! 553: register line_list the_list; ! 554: for (the_list = the_header->text; ! 555: the_list != NIL; ! 556: the_list = the_list->continuation) ! 557: put_line (the_list->string); ! 558: the_header = the_header->next; ! 559: } while (the_header != old); ! 560: put_line (""); ! 561: return; ! 562: } ! 563: ! 564: void ! 565: main (argc, argv) ! 566: int argc; ! 567: char **argv; ! 568: { ! 569: char *command_line; ! 570: header the_header; ! 571: long name_length = strlen (PROGRAM_NAME); ! 572: char buf[BUFLEN + 1]; ! 573: register int size; ! 574: FILE *the_pipe; ! 575: ! 576: my_name = MY_NAME; ! 577: the_streams = ((stream_list) NULL); ! 578: the_date = ((char *) NULL); ! 579: the_user = ((char *) NULL); ! 580: ! 581: the_header = read_header (); ! 582: command_line = alloc_string (name_length + args_size (the_header)); ! 583: strcpy (command_line, PROGRAM_NAME); ! 584: parse_header (the_header, &command_line[name_length]); ! 585: ! 586: the_pipe = popen (command_line, "w"); ! 587: if (the_pipe == ((FILE *) NULL)) ! 588: fatal ("cannot open pipe to real mailer"); ! 589: ! 590: add_a_stream (the_pipe, pclose); ! 591: ! 592: write_header (the_header); ! 593: ! 594: /* Dump the message itself */ ! 595: ! 596: while (!feof (stdin)) ! 597: { ! 598: size = fread (buf, 1, BUFLEN, stdin); ! 599: buf[size] = '\0'; ! 600: put_string (buf); ! 601: } ! 602: ! 603: exit (close_the_streams ()); ! 604: } ! 605: ! 606: #endif /* not BSD 4.2 (or newer) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.