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