// @(#)header.cc 1.4 93/08/01 // // Copyright (c) Steve Holden and Rich Burridge. // All rights reserved. // // Permission is given to distribute these sources, as long as the // copyright messages are not removed, and no monies are exchanged. // // No responsibility is taken for any errors inherent either // to the comments or the code of this program, but if reported // to me then an attempt will be made to fix them. #include #include #include #include #include #include "header.hh" #include "input.hh" #include "print.hh" extern Header hdr ; extern Input input ; extern Print prt ; // Emptyline returns true if its argument is empty or whitespace only. int Header::emptyline(char *str) { while (*str) { if (!isspace(*str)) return(0) ; str++ ; } return(1) ; } void Header::get_extra_hdrs(void) // Get user header preferences. { int i ; for (i = 0; i < input.addhdr_num; i++) get_header(input.addhdrs[i], &input.hdrs[i]) ; } // If input line is header of type 'hdr', get the contents of the header // into 'dest' (dynamically allocated). void Header::get_header(char *hdr, char **dest) { char *ptr ; int len ; // Length of the header text to the left of the colon. if (hdr_equal(hdr)) { ptr = strchr(input.nextline, ':') ; len = ptr - input.nextline + 1 ; *dest = (char *) malloc((unsigned) (strlen(input.nextline) - len + 1)) ; (void) strcpy(*dest, input.nextline + len) ; } } // If input line is header of type 'hdr', get header into dest. The header // may have multiple lines. This skips input to next line. void Header::get_mult_hdr(char *hdr, char **dest) { int i = 0 ; if (hdr_equal(hdr)) { get_header(hdr, dest) ; i++ ; input.readline() ; while (i < MAXCONT && !emptyline(input.nextline) && isspace(input.nextline[0])) { dest[i] = (char *) malloc((unsigned) (strlen(input.nextline) + 1)) ; (void) strcpy(dest[i], input.nextline) ; i++ ; input.readline() ; } dest[i] = NULL ; } } Header::Header() { int i ; from = NULL ; // From: from_ = NULL ; // From_ (UNIX from) app_from = NULL ; // Apparently_from: app_to = NULL ; // Apparently_to: for (i = 0; i < MAXCONT+1; i++) { to[i] = NULL ; // To: (can have multiple lines) cc[i] = NULL ; // Cc: (can have multiple lines) } subject = NULL ; // Subject: (can be set from command line) gsubject = NULL ; // Global subject set from command line. date = NULL ; // Date: newsgroups = NULL ; // Newsgroups: (news articles only) reply_to = NULL ; // Reply-to: content_len = NULL ; // Content-Length: } // Compare the first word of the current line (converted to lower-case, // with the given header definition. Determine if they are equal. // Allows for extra white space before the final colon. int Header::hdr_equal(char *val) { char *nptr = input.nextline ; char *wptr = val ; int n, w ; do { n = *nptr++ ; w = *wptr++ ; if (isupper(n)) n = tolower(n) ; if (isupper(w)) w = tolower(w) ; if (w == ':') while ((n == ' ' || n == '\t') && n != '\0') n = *nptr++ ; if (n != w && w != '\0') return(0) ; } while (n != '\0' && w != '\0') ; return(1) ; } // Parse_headers is a function which reads and parses the message headers, // extracting the bits which are of interest. // // The document is on standard input; the document is read up to the end of // the header; the next line is read ahead into 'nextline'. // // Parameter: // digest indicates if parsing is of digest headers instead of message // headers // // Implicit Input: // nextline contains the next line from standard input // // Side-effects: // The function fills in the global header variables with headers found. // The variable input.doc_type is set to the document type // The variable input.nextline is set // The document is read up to the line following the headers void Header::parse_headers(int digest) { char *colon ; // Pointer to colon in line. char *c ; // General character pointer. char tmpstr[MAXLINE] ; // If not processing digest headers, determine if this article is an // ordinary text file. if (!digest) // Parsing digest headers? { if (!hdr_equal(FROM_HDR)) // UNIX From_ header? { colon = strchr(input.nextline, ':') ; if (colon == NULL) // No colon => not a header line. { input.doc_type = DO_TEXT ; return ; } c = input.nextline ; while (c < colon && (!isspace(*c))) c++ ; if (c != colon) // Whitespace in header name => not header. { input.doc_type = DO_TEXT ; return ; } } } input.doc_type = DO_MAIL ; // Default to mail document. // Parse headers. while (1) { if (emptyline(input.nextline)) break ; // End of headers. if (!digest) { get_header(FROM_HDR, &from_) ; get_header(APP_FROMHDR, &app_from) ; get_header(APP_TOHDR, &app_to) ; get_header(NEWSGROUPSHDR, &newsgroups) ; get_header(NEWSGROUPHDR, &newsgroups) ; get_header(REPLYHDR, &reply_to) ; get_mult_hdr(TOHDR, to) ; if (emptyline(input.nextline)) break ; get_mult_hdr(CCHDR, cc) ; if (emptyline(input.nextline)) break ; if (input.doc_type != DO_NEWS && hdr_equal(NEWSGROUPSHDR)) input.doc_type = DO_NEWS ; if (input.doc_type != DO_NEWS && hdr_equal(NEWSGROUPHDR)) input.doc_type = DO_NEWS ; } get_header(FROMHDR, &from) ; get_header(SUBJECTHDR, &subject) ; get_header(DATEHDR, &date) ; get_extra_hdrs() ; // Get user's header preferences. if (input.content) { get_header(CONTENT_LEN, &content_len) ; if (hdr_equal(CONTENT_LEN)) { (void) sscanf(input.nextline, "%s %d", tmpstr, &input.mlen) ; // The Content-Length: doesn't seem to include the initial blank line // between the mail header and the message body, or the blank line after // the message body and before the start of the next "From " header, so add // in two for those. input.mlen += 2 ; } } if (!hdr_equal(TOHDR) && !hdr_equal(CCHDR)) { while (!input.end_of_file && !input.end_of_line) input.readline() ; // Skip rest of long lines. input.readline() ; } } } void Header::reset_headers(void) // Reset header values for next message. { int i ; if (from != NULL) (void) free(from) ; if (from_ != NULL) (void) free(from_) ; if (app_from != NULL) (void) free(app_from) ; if (app_to != NULL) (void) free(app_to) ; if (content_len != NULL) (void) free(content_len) ; if (date != NULL) (void) free(date) ; if (newsgroups != NULL) (void) free(newsgroups) ; if (reply_to != NULL) (void) free(reply_to) ; from = NULL ; from_ = NULL ; app_from = NULL ; app_to = NULL ; date = NULL ; newsgroups = NULL ; reply_to = NULL ; subject = NULL ; for (i = 0; i < MAXCONT+1; i++) { if (to[i] != NULL) (void) free(to[i]) ; to[i] = NULL ; if (cc[i] != NULL) (void) free(cc[i]) ; cc[i] = NULL ; } } // Show_headers outputs the headers in PostScript. Different headers are // output depending 'digest'. void Header::show_headers(int digest) { if (digest) { if (toprint(from, FROMHDR)) prt.show_text(T_MIXED, FROMHDR, from) ; if (toprint(subject, SUBJECTHDR)) prt.show_text(T_MIXED, SUBJECTHDR, subject) ; if (toprint(date, DATEHDR)) prt.show_text(T_MIXED, DATEHDR, date) ; } else { if (toprint(from_, FROM_HDR)) prt.show_text(T_BOLD, FROM_HDR, from_) ; if (toprint(from, FROMHDR)) prt.show_text(T_MIXED, FROMHDR, from) ; if (toprint(app_from, APP_FROMHDR)) prt.show_text(T_MIXED, APP_FROMHDR, app_from) ; if (toprint(to[0], TOHDR)) show_mult_hdr(TOHDR, to) ; if (toprint(app_to, APP_TOHDR)) prt.show_text(T_MIXED, APP_TOHDR, app_to) ; if (toprint(cc[0], CCHDR)) show_mult_hdr(CCHDR, cc) ; if (toprint(reply_to, REPLYHDR)) prt.show_text(T_MIXED, REPLYHDR, reply_to) ; if (toprint(newsgroups, NEWSGROUPSHDR)) prt.show_text(T_MIXED, NEWSGROUPSHDR, newsgroups) ; if (toprint(subject, SUBJECTHDR)) prt.show_text(T_MIXED, SUBJECTHDR, subject) ; if (toprint(date, DATEHDR)) prt.show_text(T_MIXED, DATEHDR, date) ; } prt.print_extra() ; // Print out user header preferences. cout << "sf " ; } int Header::toprint(char *hdr, char *str) { int i ; if (!hdr) return(0) ; for (i = 0; i < input.remhdr_num; i++) if (!strcasecmp(input.remhdrs[i], str)) return(0) ; return(1) ; } void Header::show_mult_hdr(char *hdr, char **val) { prt.show_text(T_MIXED, hdr, *val) ; val++ ; while (*val) prt.show_text(T_ROMAN, NULL, *val++) ; }