1 /*****************************************************************************
2 * Post for HPT (FTN NetMail/EchoMail Tosser)
3 *****************************************************************************
4 * Copyright (C) 1998-99
5 *
6 * Kolya Nesterov
7 *
8 * Fido: 2:463/7208.53
9 * Kiev, Ukraine
10 *
11 * This file is part of HPT.
12 *
13 * HPT is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2, or (at your option) any
16 * later version.
17 *
18 * HPT is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with HPT; see the file COPYING. If not, write to the Free
25 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 *****************************************************************************
27 * $Id$
28 */
29
30 /* Revision log:
31 16.12.98 - first version, written at ~1:30, in the middle of doing
32 calculation homework on Theoretical Electrics, you understood ;)
33 18.12.98 - woops forgot copyright notice, minor fixes
34 tearline generation added
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <assert.h>
44 #include <huskylib/huskylib.h>
45
46 #ifdef HAS_MALLOC_H
47 #include <malloc.h>
48 #endif
49 #ifdef HAS_SYS_SYSEXITS_H
50 #include <sys/sysexits.h>
51 #endif
52 #ifdef HAS_SYSEXITS_H
53 #include <sysexits.h>
54 #endif
55
56 #include <fidoconf/fidoconf.h>
57 #include <fidoconf/common.h>
58 #include <fidoconf/afixcmd.h>
59 #include <areafix/areafix.h>
60
61 #include <version.h>
62 #include <toss.h>
63 #include <post.h>
64 #include <global.h>
65 #include <version.h>
66 #include <hpt.h>
67 #include <scanarea.h>
68 #include <scan.h>
69 #include <hptafix.h>
70
71 #if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__)
72 /* we can't include windows.h for several reasons ... */
73 #define CharToOem CharToOemA
74 #endif
75
76 #define MAX_LINELEN 45
77 #define LINPERSECTION 0x7FFFFFFFL
78
79 #define ENCODE_BYTE(b) (((b) == 0) ? 0x60 : ((b) + 0x20))
80
81 char uu_b[] = "\"begin\" to last encoded line)\r";
82 char uu_m[] = "first to last encoded line)\r";
83 char uu_e[] = "first encoded line to \"end\")\r";
84 char uu_end[] = "end\r";
85
print_help(void)86 void print_help(void) {
87 fprintf(stdout,"\n Post a message to area:\n");
88 fprintf(stdout," hpt post [options] file\n\n");
89 fprintf(stdout," options are:\n\n");
90 fprintf(stdout," -nf \"name from\"\n");
91 fprintf(stdout," message sender's name, if not defined post uses\n");
92 fprintf(stdout," sysop name (see fidoconfig)\n\n");
93 fprintf(stdout," -nt \"name to\"\n");
94 fprintf(stdout," message receiver's name, if not defined post uses \"All\"\n\n");
95 fprintf(stdout," -af \"address from\"\n");
96 fprintf(stdout," message sender's address, if not defined post\n");
97 fprintf(stdout," uses first system address (see fidoconfig)\n\n");
98 fprintf(stdout," -at \"address to\"\n");
99 fprintf(stdout," message receiver's address, *MUST BE PRESENT FOR NETMAIL*\n\n");
100 fprintf(stdout," -s \"subject\"\n");
101 fprintf(stdout," subject line, if not defined then assumed to be empty\n\n");
102 fprintf(stdout," -e \"echo area\"\n");
103 fprintf(stdout," area to post echomail message into, if not\n");
104 fprintf(stdout," defined message is posted to netmail\n\n");
105 fprintf(stdout," -z \"tearline\"\n");
106 fprintf(stdout," tearline, if not defined then assumed to be\n");
107 fprintf(stdout," no tearline at all. Use -z \"\" to post with empty tearline\n\n");
108 fprintf(stdout," -o \"origin\"\n");
109 fprintf(stdout," origin, if not defined then assumed to be name\n");
110 fprintf(stdout," of station in config-file\n\n");
111 fprintf(stdout," -f flag(s)\n");
112 fprintf(stdout," flags to set to the posted msg. possible ones\n");
113 fprintf(stdout," are: pvt, crash, read, sent, att, fwd, orphan,\n");
114 fprintf(stdout," k/s, loc, hld, xx2, frq, rrq, cpt, arq, urq,\n");
115 fprintf(stdout," kfs, tfs, dir, imm, cfm, npd;\n");
116 fprintf(stdout," use it like this: pvt loc k/s OR pvt,loc,k/s OR \"pvt loc k/s\"\n\n");
117 fprintf(stdout," -x export message to echo links\n\n");
118 fprintf(stdout," -d erase input file after posting\n\n");
119 fprintf(stdout," -u[size] uue-multipart posting\n");
120 fprintf(stdout," size - number of lines per section (unlimited by default)\n\n");
121 fprintf(stdout," -h get help\n\n");
122 fprintf(stdout," file - text file to be posted or \"-\" for stdin\n\n");
123 exit(EX_OK);
124 }
125
init_libs(void)126 void init_libs(void)
127 {
128 struct _minf m;
129
130 if (config==NULL) processConfig();
131 /* init areafix */
132 if ( !init_hptafix() ) exit_hpt("Can't init Areafix library", 1);
133 if ( initSMAPI == -1 ) {
134 /* init SMAPI */
135 initSMAPI = 0;
136 m.req_version = 0;
137 m.def_zone = (UINT16) config->addr[0].zone;
138 if (MsgOpenApi(&m) != 0) {
139 exit_hpt("MsgApiOpen Error",1);
140 } /*endif */
141 }
142 }
143
144 struct post_parameters {
145 char *name_from; /* should be freed */
146 int name_from_len;
147 char *name_to; /* should be freed */
148 int name_to_len;
149 char *address_from;
150 char *address_to;
151 char *subject; /* should be freed */
152 int subject_len;
153 char *area_name;
154 char *tearline; /* should be freed */
155 int tearline_len;
156 char *origin; /* should be freed */
157 int origin_len;
158 long attr;
159 char *flags; /* should be freed */
160 int export_mail;
161 int erase_file;
162 int uue;
163 int sum_r;
164 char *file;
165 char *fname; /* should be freed */
166 int file_size;
167 s_area *area;
168 char *text_head; /* should be freed */
169 char *text_foot; /* should be freed */
170 int sections;
171 char *temp_file; /* should be freed */
172 long *sectioning; /* should be freed */
173 int perms;
174 };
175
free_post_parameters(struct post_parameters * p)176 void free_post_parameters(struct post_parameters *p)
177 {
178 nfree(p->name_to);
179 nfree(p->name_from);
180 nfree(p->subject);
181 nfree(p->tearline);
182 nfree(p->origin);
183 nfree(p->flags);
184 nfree(p->fname);
185 nfree(p->text_head);
186 nfree(p->text_foot);
187 nfree(p->temp_file);
188 nfree(p->sectioning);
189 }
190
strdup_convert(char ** dest,char * src)191 int strdup_convert(char **dest, char *src)
192 {
193 size_t len;
194
195 assert(dest != NULL);
196 if(src == NULL)
197 {
198 *dest = NULL;
199 return 0;
200 }
201
202 len = strlen(src);
203 *dest = malloc(len + 1);
204 if(*dest == NULL)
205 {
206 w_log(LL_CRIT, "out of memory");
207 return -1;
208 }
209
210 #ifdef __NT__
211 CharToOem(src, *dest);
212 #else
213 memcpy(*dest, src, len + 1);
214 #endif
215 return (int)len;
216 }
217
parse_post_command(struct post_parameters * p,unsigned int argc,char ** argv,unsigned int * n)218 int parse_post_command(struct post_parameters *p, unsigned int argc, char **argv, unsigned int *n)
219 {
220 char *cur_arg;
221
222 for (; *n < argc; (*n)++)
223 {
224 cur_arg = argv[*n];
225 if (*cur_arg == '-' && cur_arg[1] != '\0') {
226 switch(cur_arg[1]) {
227 case 'a': /* address */
228 if(*n + 1 >= argc)
229 goto unknown_switch;
230 if(cur_arg[2] == 't' && cur_arg[3] == 0)
231 p->address_to = argv[++*n];
232 else if(cur_arg[2] == 'f' && cur_arg[3] == 0)
233 p->address_from = argv[++*n];
234 else
235 goto unknown_switch;
236 break;
237 case 'n': /* name */
238 if(*n + 1 >= argc)
239 goto unknown_switch;
240 if(cur_arg[2] == 't' && cur_arg[3] == 0)
241 {
242 if(-1 == (p->name_to_len = strdup_convert(&p->name_to, argv[++*n])))
243 goto low_mem;
244 }
245 else if(cur_arg[2] == 'f' && cur_arg[3] == 0)
246 {
247 if(-1 == (p->name_from_len = strdup_convert(&p->name_from, argv[++*n])))
248 goto low_mem;
249 }
250 else
251 goto unknown_switch;
252 break;
253 case 'f': /* flags */
254 if(cur_arg[2] != 0)
255 goto unknown_switch;
256 for (++*n; *n < argc; ++*n) {
257 long attr = 0;
258 char *flags = NULL, *end = NULL;
259 int parsed;
260
261 parsed = parseAttrString(argv[*n], &flags, &attr, &end);
262 if(parsed <= 0 || *end != '\0')
263 {
264 nfree(flags);
265 break;
266 }
267 if ( attr ) {
268 p->attr |= attr;
269 }
270 if ( flags != NULL ) {
271 xstrscat(&p->flags, " ", flags, NULLP);
272 nfree(flags);
273 }
274 }
275 --*n;
276 break;
277 case 'e': /* echo name */
278 if(cur_arg[2] != 0 || *n + 1 >= argc)
279 goto unknown_switch;
280 p->area_name = argv[++*n];
281 break;
282 case 's': /* subject */
283 if(cur_arg[2] != 0 || *n + 1 >= argc)
284 goto unknown_switch;
285 if(-1 == (p->subject_len = strdup_convert(&p->subject, argv[++*n])))
286 goto low_mem;
287 break;
288 case 'x': /* export message */
289 if(cur_arg[2] != 0)
290 goto unknown_switch;
291 p->export_mail=1;
292 break;
293 case 'd': /* erase input file after posting */
294 if(cur_arg[2] != 0)
295 goto unknown_switch;
296 p->erase_file=1;
297 break;
298 case 'u': /* uue-multipart posting */
299 p->uue = atoi(cur_arg+2); /* TODO: additional checks would be great */
300 if(p->uue < 1) /* zero or negative */
301 p->uue = LINPERSECTION;
302 break;
303 case 'z': /* tearline */
304 if(cur_arg[2] != 0 || *n + 1 >= argc)
305 goto unknown_switch;
306 if(-1 == (p->tearline_len = strdup_convert(&p->tearline, argv[++*n])))
307 goto low_mem;
308 break;
309 case 'o': /* origin */
310 if(cur_arg[2] != 0 || *n + 1 >= argc)
311 goto unknown_switch;
312 if(-1 == (p->origin_len = strdup_convert(&p->origin, argv[++(*n)])))
313 goto low_mem;
314 break;
315 default:
316 goto unknown_switch;
317 }
318 }
319 else
320 break;
321 }
322
323 /* We discovered first non-switch argument or end of command line */
324 if(*n < argc)
325 {
326 p->file = argv[*n];
327 ++*n;
328 }
329 else
330 {
331 w_log(LL_CRIT, "post: no filename is given");
332 return 3;
333 }
334
335 return 0;
336 unknown_switch:
337 w_log(LL_CRIT, "post: unknown or incomplete switch %s", cur_arg);
338 return 1;
339 low_mem:
340 w_log(LL_CRIT, "post: low memory");
341 return 2;
342 }
343
sum_r_byte(UCHAR byte,int checksum)344 int sum_r_byte(UCHAR byte, int checksum)
345 {
346 checksum = (checksum >> 1) + ((checksum & 1) << 15); /* ror */
347 checksum += byte;
348 checksum &= 0xffff;
349 return checksum;
350 }
351
sum_r(UCHAR * buffer,int length,int checksum)352 int sum_r(UCHAR *buffer, int length, int checksum)
353 {
354 int i;
355
356 for(i = 0; i < length; ++i)
357 checksum = sum_r_byte(buffer[i], checksum);
358 return checksum;
359 }
360
361 /* in_line buffer size should be multiple of 3 zero-padded if needed */
362 /* out_line buffer should be ceiling(len/3)*4 + 1 + "\n" bytes long */
uuencode_line(UCHAR * in_line,int len,UCHAR * out_line,int * sum_r_src,int * sum_r_enc)363 int uuencode_line(UCHAR *in_line, int len, UCHAR *out_line, int *sum_r_src, int *sum_r_enc)
364 {
365 UCHAR *in_ptr = in_line, *out_ptr = out_line;
366 int i;
367
368 assert(in_line != NULL);
369 assert(out_line != NULL);
370 assert(len < 0x40);
371
372 if(sum_r_src != NULL)
373 *sum_r_src = sum_r(in_line, len, *sum_r_src);
374
375 *out_ptr++ = ENCODE_BYTE ((UCHAR)len);
376
377 /* Encode the line */
378 for (i = 0; i < len; i += 3, in_ptr += 3, out_ptr +=4)
379 {
380 /* Encode 3 bytes from the input buffer */
381 out_ptr[0] = ENCODE_BYTE ((in_ptr[0] ) >> 2);
382 out_ptr[1] = ENCODE_BYTE (((in_ptr[0] & 0x03) << 4) |
383 ((in_ptr[1] ) >> 4));
384 out_ptr[2] = ENCODE_BYTE (((in_ptr[1] & 0x0F) << 2) |
385 ((in_ptr[2] ) >> 6));
386 out_ptr[3] = ENCODE_BYTE (in_ptr[2] & 0x3F);
387 }
388
389 if(sum_r_enc != NULL)
390 {
391 *sum_r_enc = sum_r(out_line, out_ptr - out_line, *sum_r_enc);
392 *sum_r_enc = sum_r_byte(0x0a, *sum_r_enc);
393 }
394 *out_ptr++ = '\r';
395 return out_ptr - out_line;
396 }
397
uuencode_file(FILE * input,struct post_parameters * p)398 FILE *uuencode_file(FILE *input, struct post_parameters *p)
399 {
400 unsigned int part = 0, max_sections = 16, sect_size = 0;
401 int lines = 0, sum_r_sect = 0;
402 size_t linelen, outlen;
403 UCHAR inbuf[MAX_LINELEN];
404 UCHAR outbuf[MAX_LINELEN/3*4+1+1]; /* + \r + prefix */
405 FILE *tmpfile = NULL;
406 char *begin_line = NULL;
407
408 assert(MAX_LINELEN%3 == 0);
409 if((p->sectioning = malloc(sizeof(long)*max_sections)) == NULL)
410 return NULL;
411 xstrscat(&p->temp_file, config->tempOutbound, "hptucode.$$$",NULLP);
412 tmpfile = fopen(p->temp_file, "wb");
413 if (tmpfile == NULL)
414 {
415 w_log(LL_ERROR, "post: failed to open temp file %s: %s",
416 p->temp_file, strerror(errno));
417 return NULL;
418 }
419
420 p->sectioning[0] = 0;
421 /* Write the 'begin' line, giving it a mode of 0600 */
422 sect_size = xscatprintf(&begin_line, "begin %03o %s\r", p->perms, p->fname);
423 sum_r_sect = sum_r((UCHAR*)begin_line, sect_size - 1, sum_r_sect);
424 sum_r_sect = sum_r_byte(0x0a, sum_r_sect);
425 if(fwrite(begin_line, 1, sect_size, tmpfile) != sect_size)
426 { /* error */
427 nfree(begin_line);
428 fclose(input);
429 fclose(tmpfile);
430 w_log(LL_ERROR, "post: temp file write error: %s", strerror(errno));
431 return NULL;
432 }
433 nfree(begin_line);
434 do
435 {
436 if(lines >= p->uue)
437 {
438 ++part;
439 if(part + 1 >= max_sections)
440 { /* yes, alloc in advance for one element that will mark eof */
441 max_sections *= 2;
442 p->sectioning = srealloc(p->sectioning, sizeof(long)*max_sections);
443 }
444 fprintf(tmpfile, "\rsum -r/size %d/%u section (from ", sum_r_sect, sect_size);
445 if(part == 1)
446 fwrite(uu_b, sizeof(uu_b)-1, 1, tmpfile);
447 else
448 fwrite(uu_m, sizeof(uu_m)-1, 1, tmpfile);
449 p->sectioning[part] = ftell(tmpfile);
450 lines = sect_size = 0;
451 sum_r_sect = 0;
452 }
453 linelen = fread(inbuf, 1, MAX_LINELEN, input);
454 p->file_size += linelen;
455 sect_size += outlen = uuencode_line(inbuf, linelen, outbuf, &p->sum_r, &sum_r_sect);
456
457 if(fwrite(outbuf, 1, outlen, tmpfile) != outlen)
458 { /* error */
459 fclose(input);
460 fclose(tmpfile);
461 w_log(LL_ERROR, "post: temp file write error: %s", strerror(errno));
462 return NULL;
463 }
464 ++lines;
465 } while(linelen != 0);
466
467 sect_size += fwrite(uu_end, 1, sizeof(uu_end) - 1, tmpfile);
468 sum_r_sect = sum_r((UCHAR*)uu_end, sizeof(uu_end) - 2, sum_r_sect);
469 sum_r_sect = sum_r_byte(0x0a, sum_r_sect);
470
471 fprintf(tmpfile, "\rsum -r/size %d/%u section (from ", sum_r_sect, sect_size);
472 fwrite(uu_e, sizeof(uu_e)-1, 1, tmpfile);
473 fprintf(tmpfile, "sum -r/size %d/%d entire input file\r",
474 p->sum_r, p->file_size);
475
476 ++part;
477 assert(part < max_sections);
478 p->sectioning[part] = ftell(tmpfile);
479 p->sections = part;
480 p->sectioning = srealloc(p->sectioning, sizeof(long)*(p->sections + 1));
481
482 fclose(input);
483 fclose(tmpfile);
484 return fopen(p->temp_file, "rb");
485 }
486
uuencode2buf(struct post_parameters * p,char ** text,UINT msg_len,FILE * input,int part)487 UINT uuencode2buf(struct post_parameters *p, char **text, UINT msg_len, FILE *input, int part)
488 {
489 int sum_r_sect = 0, sect_size = 0, lines = 0;
490 UINT linelen, max_msg_len, outlen;
491 UCHAR inbuf[MAX_LINELEN];
492
493 if(part == 0)
494 {
495 msg_len += sect_size = xscatprintf(text,
496 "begin %03o %s\r", p->perms, p->fname);
497 sum_r_sect = sum_r((UCHAR*)*text + msg_len - sect_size,
498 sect_size - 1, sum_r_sect);
499 sum_r_sect = sum_r_byte(0x0a, sum_r_sect);
500 }
501
502 assert(MAX_LINELEN%3 == 0);
503 max_msg_len = msg_len + (MAX_LINELEN/3*4+1+1) * p->uue;
504
505 *text = srealloc(*text, max_msg_len + 1);
506 do
507 {
508 linelen = fread(inbuf, 1, MAX_LINELEN, input);
509 assert(msg_len + (MAX_LINELEN/3*4+1+1) <= max_msg_len);
510 outlen = uuencode_line(inbuf, linelen, (UCHAR*)*text + msg_len, &p->sum_r, &sum_r_sect);
511 msg_len += outlen;
512 sect_size += outlen;
513 ++lines;
514 } while(linelen != 0 && lines < p->uue);
515 (*text)[msg_len] = '\0';
516 if(linelen == 0)
517 {
518 xstrcat(text, uu_end);
519 msg_len += sizeof(uu_end)-1;
520 sect_size += sizeof(uu_end)-1;
521 sum_r_sect = sum_r((UCHAR*)uu_end, sizeof(uu_end)-2, sum_r_sect);
522 sum_r_sect = sum_r_byte(0x0a, sum_r_sect);
523 msg_len += xscatprintf(text, "\rsum -r/size %d/%u section (from %s",
524 sum_r_sect, sect_size, uu_e);
525 msg_len += xscatprintf(text, "sum -r/size %d/%d entire input file\r",
526 p->sum_r, p->file_size);
527 }
528 else
529 {
530 if(part == 0)
531 msg_len += xscatprintf(text, "\rsum -r/size %d/%u section (from %s",
532 sum_r_sect, sect_size, uu_b);
533 else
534 msg_len += xscatprintf(text, "\rsum -r/size %d/%u section (from %s",
535 sum_r_sect, sect_size, uu_m);
536 }
537 return msg_len;
538 }
539
open_input_file(struct post_parameters * p)540 FILE *open_input_file(struct post_parameters *p)
541 {
542 FILE *input = NULL;
543
544 if (p->file == NULL)
545 return NULL;
546
547 if (p->file[0] == '-' && p->file[1] == 0)
548 {
549 if(p->uue)
550 w_log(LL_CRIT, "post: uuencoding of stdin is not implemented");
551 else
552 input = stdin;
553 }
554 else if(fexist(p->file))
555 {
556 input = fopen(p->file, (p->uue)?"rb":"rt");
557 if(input == NULL)
558 {
559 w_log(LL_ERROR, "post: failed to open input file %s: %s",
560 p->file, strerror(errno));
561 }
562 else if(p->uue) /* Calculate number of sections */
563 {
564 long file_size, lines;
565
566 p->perms = 0644;
567 #ifdef __UNIX__
568 {
569 struct stat st;
570 if (fstat(fileno(input), &st) == 0)
571 p->perms = st.st_mode & 0777;
572 }
573 #else
574 if (patimat(p->file, "*.exe") ||
575 patimat(p->file, "*.com"))
576 p->perms = 0755;
577 #endif
578
579 file_size = fsize(p->file);
580 if(file_size < 0)
581 {
582 /* no precalculation is possible for this file
583 * or on current platform, fallback to temp file */
584 input = uuencode_file(input, p);
585 }
586 else
587 {
588 lines = (file_size + MAX_LINELEN - 1) / MAX_LINELEN + 1; /* +1 for zero-len line */
589 p->sections = (lines + p->uue - 1) / p->uue;
590 p->file_size = file_size;
591 }
592 }
593 }
594 else
595 w_log(LL_ERROR, "post: input file '%s' does not exist", p->file);
596 return input;
597 }
598
process_parameters(struct post_parameters * p,s_message * msg)599 int process_parameters(struct post_parameters *p, s_message *msg)
600 {
601 int result = 0;
602
603 /* Copy given values or set defaults */
604 if(p->name_to != NULL)
605 {
606 msg->toUserName = p->name_to;
607 p->name_to = NULL;
608 }
609 else
610 {
611 msg->toUserName = safe_strdup("All");
612 p->name_to_len = 3;
613 }
614
615 if(p->name_from != NULL)
616 {
617 msg->fromUserName = p->name_from;
618 p->name_from = NULL;
619 }
620 else
621 {
622 msg->fromUserName = safe_strdup(config->sysop);
623 p->name_from_len = strlen(config->sysop);
624 }
625
626 if (p->subject != NULL)
627 {
628 msg->subjectLine = p->subject;
629 p->subject = NULL;
630 }
631 else
632 msg->subjectLine = safe_calloc(1, 1);
633
634 strdup_convert(&p->fname, GetFilenameFromPathname(p->file));
635
636 /* Choose where to post */
637 if(p->area_name != NULL)
638 {
639 p->area = getNetMailArea(config, p->area_name);
640 if (p->area == NULL)
641 {
642 p->area = getArea(config, p->area_name);
643 if (p->area == &(config->badArea)) {
644 w_log(LL_ERROR, "post: wrong area to post: %s", p->area_name);
645 return 1;
646 }
647 } else /* found NetmailArea */
648 msg->netMail = 1;
649 }
650 else /* first netmail area is default */
651 {
652 msg->netMail = 1;
653 p->area = &(config->netMailAreas[0]);
654 }
655
656 /* Decide on addresses */
657 assert(p->area != NULL);
658 if(p->address_from != NULL)
659 {
660 /* set defaults */
661 msg->origAddr.zone = config->addr[0].zone;
662 msg->origAddr.net = config->addr[0].net;
663 result = parseFtnAddrZ(p->address_from, &(msg->origAddr), FTNADDR_NODE, NULL);
664 if(result & FTNADDR_ERROR)
665 {
666 w_log(LL_ERROR, "post: wrong 'from' address: %s", p->address_from);
667 return 1;
668 }
669 }
670 else
671 msg->origAddr = p->area->useAka[0];
672
673 if(msg->netMail == 1)
674 {
675 if(p->address_to)
676 {
677 /* set defaults */
678 msg->destAddr.zone = msg->origAddr.zone;
679 msg->destAddr.net = msg->origAddr.net;
680 result = parseFtnAddrZ(p->address_to, &msg->destAddr, FTNADDR_NODE, NULL);
681 if(result & FTNADDR_ERROR)
682 {
683 w_log(LL_ERROR, "post: wrong 'to' address: %s", p->address_to);
684 return 1;
685 }
686 }
687 else
688 {
689 w_log(LL_ERROR, "post: attempt to post netmail msg without specifying dest. address");
690 return 1;
691 }
692 }
693
694 /* Copy attributes */
695 msg->attributes |= p->attr;
696
697 /* Create header for message(s) text */
698 /* createKludges shouldn't be called here since it generate MSGID */
699
700 if ((p->export_mail || !p->area->fileName) && !config->disableTID)
701 xscatprintf(&p->text_head, "\001TID: %s\r", versionStr);
702
703 if (p->flags) xscatprintf(&p->text_head, "\001FLAGS%s\r", p->flags);
704
705 /* Create footer for message(s) text */
706 xscatprintf(&p->text_foot, "\r");
707 if (!msg->netMail || p->tearline)
708 {
709 if(p->tearline_len > (79-4))
710 p->tearline[79-4] = '\0';
711 /* tearline in config supposed to be of acceptable length */
712 xscatprintf(&p->text_foot, "--- %s\r",
713 (p->tearline) ? p->tearline : (config->tearline) ? config->tearline : "");
714 }
715 if (!msg->netMail || p->origin)
716 {
717 char *origAddr = aka2str(msg->origAddr);
718 int origLen = 11 + 3 + /* " * Origin: " + " ()" */
719 strlen(origAddr);
720 assert(origLen < 79);
721 if(p->origin == NULL)
722 {
723 p->origin = safe_strdup((config->origin) ? config->origin : config->name);
724 p->origin_len = strlen(p->origin);
725 }
726 if(origLen + p->origin_len > 79)
727 p->origin[79 - origLen] = '\0';
728 xscatprintf(&p->text_foot, " * Origin: %s (%s)\r",
729 p->origin, aka2str(msg->origAddr));
730 }
731
732 /* recoding from internal to transport charSet */
733 if (config->outtab != NULL) {
734 recodeToTransportCharset((char*)msg->fromUserName);
735 recodeToTransportCharset((char*)msg->toUserName);
736 recodeToTransportCharset((char*)msg->subjectLine);
737 }
738 return 0;
739 }
740
process_input_file(struct post_parameters * p,FILE * input,s_message * msg,int * part)741 void process_input_file(struct post_parameters *p, FILE *input, s_message *msg, int *part)
742 {
743 UINT msg_len;
744
745 msg_len = strlen(msg->text);
746 if( p->uue )
747 {
748 msg_len += xscatprintf(&msg->text, "\rsection %d of %d of file %s < %s >\r\r",
749 *part + 1, p->sections, p->fname, versionStr);
750 if (*part > 0)
751 msg->subjectLine[p->subject_len]='\0';
752 xscatprintf(&msg->subjectLine, " [%d/%d]", *part + 1, p->sections);
753
754 if(p->temp_file != NULL) /* Load uu-code from temp file */
755 {
756 int to_read, was_read;
757 to_read = p->sectioning[*part + 1] - p->sectioning[*part];
758 msg->text = srealloc(msg->text, msg_len + to_read + 1);
759 msg_len += was_read = fread(msg->text + msg_len, 1, to_read, input);
760 msg->text[msg_len] = '\0';
761 if(was_read != to_read)
762 { /* error */
763 w_log(LL_ERROR, "post: temp file read error: %s", strerror(errno));
764 /* Continue anyway */
765 }
766 }
767 else /* Encode on the fly based on size prediction */
768 {
769 msg_len = uuencode2buf(p, &msg->text, msg_len, input, *part);
770 }
771 /* msg_len += xscatprintf(&msg->text,"section %d end\r", *part + 1); */
772
773 ++*part;
774 }
775 else /* Ordinary text paste */
776 {
777 int c;
778 UINT cursize = msg_len;
779 for (; msg_len < 4*1024*1024; ++msg_len) /* impose reasonable restriction on max_len */
780 {
781 c = getc(input);
782 /* FIXME: Maybe fread with file opened in text mode and replace \n->\r will do better? */
783 if (c == EOF || c == 0)
784 break;
785
786 if (msg_len >= cursize)
787 msg->text = safe_realloc(msg->text,
788 (cursize += TEXTBUFFERSIZE) + 1);
789
790 msg->text[msg_len] = (char)c;
791 if ('\r' == c)
792 --msg_len;
793 if ('\n' == c)
794 msg->text[msg_len] = '\r';
795 }
796 msg->text[msg_len] = 0; /* always ok because buffer's size is (cursize + 1) */
797 if(input == stdin)
798 while(!feof(input)) getc(input);
799 }
800 }
801
do_posting(struct post_parameters * p,FILE * text,s_message * msg)802 void do_posting(struct post_parameters *p, FILE *text, s_message *msg)
803 {
804 int part = 0;
805
806 w_log(LL_START, "Start posting...");
807 do
808 {
809 msg->text = createKludges(config,
810 (msg->netMail == 0) ? strUpper(p->area_name) : NULL,
811 &msg->origAddr,
812 &msg->destAddr,
813 versionStr);
814
815 xstrcat(&msg->text, p->text_head);
816 process_input_file(p, text, msg, &part);
817 if (msg->text[0] && msg->text[strlen(msg->text)-1] != '\r')
818 xstrcat(&msg->text, p->text_foot);
819 else
820 xstrcat(&msg->text, p->text_foot + 1);
821
822 msg->textLength = strlen(msg->text);
823
824 w_log(LL_POSTING,
825 "Posting msg from %u:%u/%u.%u -> %s in area: %s with subject: %s",
826 msg->origAddr.zone, msg->origAddr.net,
827 msg->origAddr.node, msg->origAddr.point,
828 msg->netMail ? aka2str(msg->destAddr) : msg->toUserName,
829 (p->area_name) ? p->area_name : p->area->areaName,
830 msg->subjectLine);
831
832 /* recoding from internal to transport charSet */
833 if (config->outtab != NULL) {
834 recodeToTransportCharset((char*)msg->text);
835 }
836
837 if (!p->export_mail && p->area->fileName) {
838 msg->recode &= ~(REC_HDR|REC_TXT); /* msg in transport Charset */
839 putMsgInArea(p->area, msg, 1, msg->attributes);
840 }
841 else {
842 if (msg->netMail) {
843 processNMMsg(msg, NULL, NULL, 0, MSGLOCAL);
844 } else {
845 processEMMsg(msg, *(p->area->useAka), 1, (MSGSCANNED|MSGSENT|MSGLOCAL));
846 }
847 }
848 nfree(msg->text);
849 } while (part < p->sections);
850
851 if (p->export_mail)
852 {
853 closeOpenedPkt();
854 tossTempOutbound(config->tempOutbound);
855 writeDupeFiles();
856 }
857
858 if ((config->echotosslog) && (!p->export_mail)) {
859 FILE *f=fopen(config->echotosslog, "a");
860 if (f==NULL)
861 w_log(LL_ERROR, "Could not open or create EchoTossLogFile.");
862 else {
863 fprintf(f, "%s\n", p->area->areaName);
864 fclose(f);
865 }
866 }
867 w_log(LL_STOP, "End posting");
868 }
869
post(int c,unsigned int * n,char * params[])870 void post(int c, unsigned int *n, char *params[])
871 {
872 struct post_parameters p = {0};
873 FILE *text = NULL;
874 s_message msg = {{0}};
875 time_t t = time (NULL);
876 struct tm *tm;
877
878 if (params[*n]!='\0' && params[*n][1]=='h')
879 print_help(); /* exit */
880
881 if(parse_post_command(&p, c, params, n))
882 {
883 free_post_parameters(&p);
884 print_help(); /* exit */
885 }
886 --*n;
887
888 init_libs();
889
890 if(process_parameters(&p, &msg))
891 {
892 free_post_parameters(&p);
893 return;
894 }
895
896 if((text = open_input_file(&p)) == NULL)
897 {
898 free_post_parameters(&p);
899 return;
900 }
901
902 /* won't be set in the msgbase, because the mail is processed if it were received */
903 tm = localtime(&t);
904 fts_time((char *)msg.datetime, tm);
905
906 /* actual read from file and write to messagebase/pkt */
907 do_posting(&p, text, &msg);
908
909 /* Cleanup */
910 if (!(p.file[0] == '-' && p.file[1] == 0))
911 {
912 fclose(text);
913 if (p.erase_file)
914 remove(p.file);
915 }
916 if(p.temp_file)
917 remove(p.temp_file);
918
919 freeMsgBuffers(&msg);
920 free_post_parameters(&p);
921
922 /* deinit SMAPI */
923 MsgCloseApi();
924 }
925