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