1 2 /* 3 * The "sndparts" routines manage chunks of outgoing messages. 4 * In the simplest case, there will be a single part that corresponds 5 * to the outbound mail message. These routines provide support to 6 * add attachments and inclusions, as well as complex parts such 7 * as the MIME "multipart/mixed" type. 8 */ 9 10 /* 11 * RFC-1521 (sec 4.5.3) says 7bit/8bit parts cannot exceed this length 12 * Actually, the max is 1000, but we've accounted for CRNL termination here. 13 */ 14 #define RFC821_MAXLEN 998 15 16 /* generate maximally random/minimally ugly multipart separator */ 17 #define MIME_MAKE_BOUNDARY(buf, type, seq) \ 18 sprintf(buf, "%%--%s-boundary-%d.%d.%lu--%%", \ 19 (type), (seq), getpid(), \ 20 (unsigned long)time((time_t *)NULL)); 21 22 /* commands that handle various content encodings */ 23 # define MIME_ENCODE_CMD_QUOTED(buf, infile, outfile) \ 24 sprintf((buf), "mmencode -q %s >%s", (infile), (outfile)) 25 # define MIME_ENCODE_CMD_BASE64(buf, infile, outfile) \ 26 sprintf((buf), "mmencode -b %s >%s", (infile), (outfile)) 27 # define MIME_ENCODE_CMD_UUENCODE(buf, infile, outfile) \ 28 sprintf((buf), "uuencode %s <%s >%s", \ 29 basename(infile), (infile), (outfile)) /* SIDE EFFECTS */ 30 31 /* command that provides information on the content of a part */ 32 # define MIME_FILE_CMD(buf, infile, outfile) \ 33 sprintf((buf), "file %s >%s", (infile), (outfile)) 34 35 36 /* 37 * A (SEND_BODYPART) describes a chunk of data being sent. In the 38 * simplest case (a plain old mail message) there is just a single 39 * part representing the message. Additional parts will be used 40 * as attachments and inclusions are created. 41 */ 42 43 /* part_type settings for a (SEND_BODYPART) */ 44 #define BP_IS_DUMMY 0 /* not a real part */ 45 #define BP_IS_MSSGTEXT 1 /* text/plain subject to [...] interp */ 46 #define BP_IS_MIMEPART 2 /* a regular MIME body part */ 47 #define BP_IS_MULTIPART 3 /* head of a multipart */ 48 49 /* content_header[] selectors */ 50 #define BP_CONT_TYPE 0 /* Content-Type */ 51 #define BP_CONT_ENCODING 1 /* Content-Transfer-Encoding */ 52 #define BP_CONT_DESCRIPTION 2 /* Content-Description */ 53 #define BP_CONT_DISPOSITION 3 /* Content-Disposition */ 54 #define BP_CONT_MD5 4 /* Content-MD5 */ 55 #define BP_NUM_CONT_HEADERS 5 56 57 /* the header names associated with the above */ 58 extern char *Mime_header_names[BP_NUM_CONT_HEADERS]; 59 60 #ifdef ANSI_C 61 struct send_multipart; 62 #endif 63 64 /* 65 * The (SEND_BODYPART) describes a chunk of the message body. 66 */ 67 typedef struct send_bodypart { 68 69 /* 70 * The "part_type" indicate what this part contains. The remaining 71 * members of the structure are interpreted according to the type. 72 * 73 * BP_IS_DUMMY - Not a real part. This is used in the attachments 74 * menu to create labels. The only member of the structure that 75 * is valid for one of these is "fname", which contains a label. 76 * Never ever try to output one of these! 77 * 78 * BP_IS_MIMEPART - This part is a single entity, such as a 79 * file attachment. The MIME header information and the content 80 * statistics members will be valid. The multipart information, 81 * however, does not contain meaningful information. Except 82 * for the main message (which will be a BP_IS_MSSGTEXT), every 83 * chunk of data is represented by one of these. 84 * 85 * BP_IS_MULTIPART - This part does not contain any data, but 86 * instead represents a chunk of parts, a "multipart/mixed". In 87 * this case, the multipart members are valid, and will lead 88 * to the parts that comprise this multipart. The MIME header 89 * and content statistics members should be ignored. 90 * ("multipart/mixed" is the only form of multipart supported at 91 * this time.) 92 * 93 * BP_IS_MSSGTEXT - This part represents the message entered by 94 * the user. The MIME header and content statistics members 95 * describe the message text. The multipart information will 96 * indicate whether the user has provided any attachments or 97 * inclusions. If the multipart list is empty, this message 98 * is sent as a simple "text/plain". If there is multipart 99 * information, then the message is a "multipart/mixed", with 100 * this text appearing with one (or more) subparts. 101 */ 102 int part_type; 103 104 /* 105 * The (SEND_MULTIPART) structure is just a list of these 106 * (SEND_BODYPART) pieces. It is possible to have a body part 107 * appear in multiple lists. (For instance, it could appear 108 * in the list of attachments for a BP_IS_MSSGTEXT part, as well 109 * as a separate list that tracks the attachments that were 110 * created by the attachments menu.) The "link_count" indicates 111 * how many (SEND_MULTIPART) lists reference this part. When 112 * the link count reaches zero, this part no longer is in use 113 * and may be destroyed. 114 */ 115 int link_count; 116 117 /* 118 * The file that contains the data for this part. 119 * BP_IS_DUMMY - a text label. 120 * BP_IS_MIMEPART - filename containing part data. 121 * BP_IS_MULTIPART - undefined value, do not use. 122 * BP_IS_MSSGTEXT - filename containing message text. 123 */ 124 char *fname; 125 126 /* 127 * Procedures that emit the part header and body. 128 * BP_IS_DUMMY - undefined values, do not use. 129 * BP_IS_MIMEPART - procedures to emit part header and body. 130 * BP_IS_MULTIPART - procedures to emit the multipart hdr and body. 131 * BP_IS_MSSGTEXT - procedures to emit message (and attachments and 132 * inclusions) header and body. 133 */ 134 int (*emit_hdr_proc) P_((FILE *, struct send_bodypart *)); 135 int (*emit_body_proc) P_((FILE *, struct send_bodypart *)); 136 137 /* 138 * Values of the MIME "Content-" headers. 139 * BP_IS_DUMMY - undefined values, do not use. 140 * BP_IS_MIMEPART - valid header values. 141 * BP_IS_MULTIPART - undefined values, do not use. 142 * BP_IS_MSSGTEXT - header values associated with the message text. 143 * If the message will be transmitted as "text/plain" then 144 * these appear in the main message headers. If the message 145 * is "multipart/mixed" then these appear in the part 146 * that contains the message text. 147 */ 148 char *content_header[BP_NUM_CONT_HEADERS]; 149 150 /* 151 * Statistics on the data. 152 * BP_IS_DUMMY - undefined values, do not use. 153 * BP_IS_MIMEPART - valid statistics on the part data. 154 * BP_IS_MULTIPART - undefined values, do not use. 155 * BP_IS_MSSGTEXT - valid statistics on the message text. 156 */ 157 long total_chars; /* size of the part */ 158 long ascii_chars; /* chars 0x20 thru 0x7F plus whitespace */ 159 long binlo_chars; /* non-space chars < 0x20 (incl 0x0!) */ 160 long binhi_chars; /* chars >= 0x80 */ 161 int max_linelen; /* length of longest line, excluding NL */ 162 163 /* 164 * Multipart information. 165 * BP_IS_DUMMY - undefined values, do not use. 166 * BP_IS_MIMEPART - undefined values, do not use. 167 * BP_IS_MULTIPART - lists the parts that comprise this multipart. 168 * BP_IS_MSSGTEXT - the attachments and inclusions for the 169 * message. If the list is empty then there are none 170 * and the message will be sent as "text/plain". 171 */ 172 struct send_multipart *subparts; 173 char *boundary; /* multipart boundary seperator */ 174 175 } SEND_BODYPART; 176 177 178 /* 179 * A multipart list is constructed with (SEND_MULTIPART). For a list 180 * with N parts, there will be N+1 (SEND_MULTIPART) entries. One serves 181 * as the list head, and the remainder encapsulate a (SEND_BODYPART) 182 * that contains the data for the corresponding part. 183 */ 184 typedef struct send_multipart { 185 186 /* 187 * A part may be keyed with an ID number. This is optional, and is 188 * required only if a lookup-by-ID will be performed. This is 189 * used, for instance, by the [include] feature. When initially 190 * scanning the user's message, the included parts are keyed by 191 * fseek position in the file. This means that when the final 192 * output is produced, the part can be located easily without 193 * reparsing the input. On the other hand, the [attach] parts 194 * are not keyed, since no lookup is performed (they merely are 195 * dumped out when the message text is complete). 196 */ 197 long id; 198 199 /* 200 * The "part" is the (SEND_BODYPART) that contains the data for 201 * this part. The list head will have a NULL value here. 202 */ 203 struct send_bodypart *part; 204 205 /* 206 * Forward and back pointers for double-linked list. 207 */ 208 struct send_multipart *prev, *next; 209 210 } SEND_MULTIPART; 211 212 213 /* operations that may be performed on the head element of a (SEND_MULTIPART) */ 214 #define MULTIPART_HEAD(mp) ((mp)->next) 215 #define MULTIPART_TAIL(mp) ((mp)->prev) 216 #define MULTIPART_IS_EMPTY(mp) ((mp)->next == (mp)) 217 218 /* operations that may be performed on any element of a (SEND_MULTIPART) */ 219 #define MULTIPART_PART(mp) ((mp)->part) 220 #define MULTIPART_ID(mp) ((mp)->id) 221 222 /* ID used for attachment parts */ 223 #define MP_ID_ATTACHMENT (-1L) 224 225 226 /* sndpart_lib.c */ 227 228 int encoding_is_reasonable P_((const char *)); 229 230 SEND_BODYPART *bodypart_new P_((const char *, int)); 231 void bodypart_destroy P_((SEND_BODYPART *)); 232 void bodypart_set_content P_((SEND_BODYPART *, int, const char *)); 233 const char *bodypart_get_content P_((SEND_BODYPART *, int)); 234 void bodypart_guess_content P_((SEND_BODYPART *, int)); 235 236 #define bodypart_get_filename(part) ((part)->fname) 237 238 SEND_MULTIPART *multipart_new P_((SEND_BODYPART *, long)); 239 void multipart_destroy P_((SEND_MULTIPART *)); 240 SEND_MULTIPART *multipart_insertpart P_((SEND_MULTIPART *, SEND_MULTIPART *, SEND_BODYPART *, long)); 241 SEND_MULTIPART *multipart_appendpart P_((SEND_MULTIPART *, SEND_MULTIPART *, SEND_BODYPART *, long)); 242 SEND_BODYPART *multipart_deletepart P_((SEND_MULTIPART *, SEND_MULTIPART *)); 243 SEND_MULTIPART *multipart_next P_((SEND_MULTIPART *, SEND_MULTIPART *)); 244 SEND_MULTIPART *multipart_find P_((SEND_MULTIPART *, long)); 245 246 #ifdef NDEBUG 247 # define bodypart_integrity_check(part) 248 # define multipart_integrity_check(part) 249 #else 250 void bodypart_integrity_check P_((const SEND_BODYPART *)); 251 void multipart_integrity_check P_((const SEND_MULTIPART *)); 252 #endif 253 254 255 /* sndpart_io.c */ 256 257 SEND_BODYPART *newpart_mssgtext P_((const char *)); 258 SEND_BODYPART *newpart_mimepart P_((const char *)); 259 260 int emitpart P_((FILE *, SEND_BODYPART *)); 261 int emitpart_mssghdr P_((FILE *, SEND_BODYPART *)); 262 int emitpart_mssgbody P_((FILE *, SEND_BODYPART *)); 263 264