1 /*****************************************************************************
2  * Posting text files to pkt.
3  *****************************************************************************
4  * (c) 1999-2002 Husky team
5  *
6  * This file is part of HPT, part of Husky project.
7  *
8  * HPT is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2, or (at your option) any
11  * later version.
12  *
13  * HPT is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with HPT; see the file COPYING.  If not, write to the Free
20  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA
21  * or download it from http://www.gnu.org site.
22  *****************************************************************************
23  * $Id$
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <errno.h>
31 #include <ctype.h>
32 
33 /* compiler.h */
34 #include <huskylib/compiler.h>
35 #include <huskylib/huskylib.h>
36 
37 #ifdef HAS_UNISTD_H
38 #include <unistd.h>
39 #endif
40 
41 #ifdef HAS_DOS_H
42 #include <dos.h>
43 #endif
44 
45 #if defined(HAS_SYS_SYSEXITS_H)
46 #include <sys/sysexits.h>
47 #endif
48 #if defined(HAS_SYSEXITS_H)
49 #include <sysexits.h>
50 #endif
51 
52 #if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__)
53 /* we can't include windows.h to prevent type redefinitions ... */
54 #define CharToOem CharToOemA
55 #endif
56 
57 /*  fidoconf */
58 #include <fidoconf/fidoconf.h>
59 #include <fidoconf/common.h>
60 #include <huskylib/xstr.h>
61 #include <fidoconf/afixcmd.h>
62 #include <huskylib/recode.h>
63 
64 #include <areafix/areafix.h>
65 
66 /* hpt */
67 #include <global.h>
68 #include <pkt.h>
69 #include <version.h>
70 #include <cvsdate.h>
71 
72 #define clean_exit(exitcode)   { \
73                                 nfree(msg.fromUserName); \
74                                 nfree(msg.toUserName);   \
75                                 nfree(msg.subjectLine);  \
76                                 exit(exitcode);          \
77                                }
78 static int quiet_mode = 0; /* quiet mode flag */
79 
main(int argc,char * argv[])80 int main(int argc, char *argv[])
81 {
82     s_pktHeader  header;
83     s_message    msg;
84     FILE         *pkt;
85     time_t       t;
86     struct tm    *tm;
87     char *area = NULL, *passwd = NULL, *tearl = NULL, *orig = NULL, *dir = NULL;
88     FILE *text = NULL;
89     int quit=0, n = 1;
90     char *textBuffer = NULL;
91     char *versionStr=NULL;
92     char *tmp = NULL, *fileName = NULL;
93     char *cfgFile = NULL;
94 
95     memset (&header,'\0',sizeof(s_pktHeader));
96     memset (&msg,'\0',sizeof(s_message));
97 
98    versionStr = GenVersionStr( "txt2pkt", VER_MAJOR, VER_MINOR, VER_PATCH,
99                                VER_BRANCH, cvs_date );
100 
101    if (argc == 1) {
102        printf("%s\n\n", versionStr);
103 
104        printf("Usage: txt2pkt [options] <file>|-\n"
105              "Options:\n"
106              "\t -q          \t- quiet mode\n"
107              "\t -c \"<file>\" \t- configuration file\n"
108              "\t -xf \"<arg>\" \t- packet from address\n"
109              "\t -xt \"<arg>\" \t- packet to address\n"
110              "\t -p  \"<arg>\" \t- packet password\n"
111              "\t -af \"<arg>\" \t- message from address\n"
112              "\t -at \"<arg>\" \t- message to address\n"
113              "\t -nf \"<arg>\" \t- message from name\n"
114              "\t -nt \"<arg>\" \t- message to name\n"
115              "\t -e  \"<arg>\" \t- message echo name\n");
116       printf("\t -t  \"<arg>\" \t- message tearline\n"
117              "\t -o  \"<arg>\" \t- message origin\n"
118              "\t -s  \"<arg>\" \t- message subject\n"
119              "\t -d  \"<path>\" \t- output directory\n"
120              "\t <file> or -\t- text file to post. the '-' sign for standard input\n");
121       exit(EX_OK);
122    }
123 
124    for (; n < argc; n++) {
125       if (*argv[n] == '-' && argv[n][1]) {
126          switch(argv[n][1]) {
127             case 'c':    /*  config  */
128                if(argv[n][2])
129                  cfgFile = argv[n]+2;
130                else if(++n<argc)
131                  cfgFile = argv[n];
132                else {
133                  fprintf(stderr,"-c: Parameter (filename) is required\n");
134                  clean_exit(EX_USAGE);
135                }
136                break;
137             case 'a':    /*  address */
138                switch(argv[n][2]) {
139                   case 'f':
140                     if(argv[n][3])
141                       tmp=argv[n]+3;
142                     else if(++n<argc)
143                       tmp=argv[n];
144                     else {
145                       fprintf(stderr,"-af: Parameter (FTN address) is required\n");
146                       clean_exit(EX_USAGE);
147                     }
148                     if(parseFtnAddrZS(tmp, &(msg.origAddr)) & FTNADDR_ERROR) {
149                       fprintf(stderr,"-af: Invalid FTN address\n");
150                       clean_exit(EX_USAGE);
151                     }
152                     tmp=NULL;
153                     break;
154                   case 't':
155                     if(argv[n][3])
156                       tmp=argv[n]+3;
157                     else if(++n<argc)
158                       tmp=argv[n];
159                     else {
160                       fprintf(stderr,"-at: Parameter (FTN address) is required\n");
161                       clean_exit(EX_USAGE);
162                     }
163                     if(parseFtnAddrZS(tmp, &(msg.destAddr)) & FTNADDR_ERROR) {
164                       fprintf(stderr,"-at: Invalid FTN address\n");
165                       clean_exit(EX_USAGE);
166                     }
167                     tmp=NULL;
168                     break;
169                   default:
170                      quit = 1;
171                      break;
172                }
173                break;
174             case 'x':    /*  address */
175                switch(argv[n][2]) {
176                   case 'f':
177                      if(argv[n][3])
178                        tmp=argv[n]+3;
179                      else if(++n<argc)
180                        tmp=argv[n];
181                      else {
182                        fprintf(stderr,"-xf: Parameter (FTN address) is required\n");
183                        clean_exit(EX_USAGE);
184                      }
185                      if(parseFtnAddrZS(tmp, &(header.origAddr)) & FTNADDR_ERROR) {
186                        fprintf(stderr,"-xf: Invalid FTN address\n");
187                        clean_exit(EX_USAGE);
188                      }
189                      tmp=NULL;
190                      break;
191                   case 't':
192                      if(argv[n][3])
193                        tmp=argv[n]+3;
194                      else if(++n<argc)
195                        tmp=argv[n];
196                      else {
197                        fprintf(stderr,"-xt: Parameter (FTN address) is required\n");
198                        clean_exit(EX_USAGE);
199                      }
200                      if(parseFtnAddrZS(tmp, &(header.destAddr)) & FTNADDR_ERROR) {
201                        fprintf(stderr,"-xt: Invalid FTN address\n");
202                        clean_exit(EX_USAGE);
203                      }
204                      tmp=NULL;
205                      break;
206                   default:
207                      quit = 1;
208                      break;
209                }
210                break;
211             case 'n':    /*  name */
212                switch(argv[n][2]) {
213                   case 't':
214                      if(argv[n][3])
215                        tmp=argv[n]+3;
216                      else if(++n<argc)
217                        tmp=argv[n];
218                      else {
219                        fprintf(stderr,"-nt: Parameter (name) is required\n");
220                        clean_exit(EX_USAGE);
221                      }
222                      if (strlen(tmp)>36) { /* Max "to" name, see FTS-1 */
223                        fprintf(stderr,"-nt: Name too long, truncated to 36 characters.\n");
224                        tmp[36]='\0';
225                      }
226                      msg.toUserName = sstrdup(tmp);
227                      tmp=NULL;
228 #ifdef __NT__
229                      CharToOem(msg.toUserName, msg.toUserName);
230 #endif
231                      break;
232                   case 'f':
233                      if(argv[n][3])
234                        tmp=argv[n]+3;
235                      else if(++n<argc)
236                        tmp=argv[n];
237                      else {
238                        fprintf(stderr,"-nf: Parameter (name) is required\n");
239                        clean_exit(EX_USAGE);
240                      }
241                      if (strlen(tmp)>36) { /* Max "from" name, see FTS-1 */
242                        fprintf(stderr,"-nf: Name too long, truncated to 36 characters.\n");
243                        tmp[36]='\0';
244                      }
245                      msg.fromUserName = sstrdup(tmp);
246                      tmp=NULL;
247 #ifdef __NT__
248                      CharToOem(msg.fromUserName, msg.fromUserName);
249 #endif
250                      break;
251                   default:
252                      quit = 1;
253                      break;
254                }
255                break;
256             case 'e':    /*  echo name */
257                if(argv[n][2])
258                  area = argv[n]+2;
259                else if(++n<argc)
260                  area = argv[n];
261                else {
262                  fprintf(stderr,"-e: Parameter (areatag) is required\n");
263                  clean_exit(EX_USAGE);
264                }
265                for(tmp=area; *tmp; tmp++){
266                  if (iscntrl(*tmp) || isspace(*tmp)) {
267                    fprintf(stderr, "-e: Areatag is contains invalid character '%c'\n", *tmp);
268                    clean_exit(EX_USAGE);
269                  }
270                }
271                tmp=NULL;
272                break;
273             case 'p':    /*  password */
274               if(argv[n][2])
275                 passwd = argv[n]+2;
276               else if(++n<argc)
277                 passwd = argv[n];
278               else {
279                 fprintf(stderr,"-p: Parameter (passowrd, 8 chars) is required\n");
280                 clean_exit(EX_USAGE);
281               }
282               if (strlen(passwd)>8) {
283                 fprintf(stderr, "Password too long, truncated to 8 characters\n");
284                  passwd[8] = '\0';
285                }
286                break;
287             case 't':    /*  tearline */
288                if(argv[n][2])
289                  tearl = argv[n]+2;
290                else if(++n<argc)
291                  tearl = argv[n];
292                else {
293                  fprintf(stderr,"-t: Parameter (tearline text) is required\n");
294                  clean_exit(EX_USAGE);
295                }
296 #ifdef __NT__
297                CharToOem(tearl, tearl);
298 #endif
299                break;
300             case 'o':    /*  origin */
301                if(argv[n][2])
302                  orig = argv[n]+2;
303                else if(++n<argc)
304                  orig = argv[n];
305                else {
306                  fprintf(stderr,"-o: Parameter (origin) is required\n");
307                  clean_exit(EX_USAGE);
308                }
309 #ifdef __NT__
310                CharToOem(orig, orig);
311 #endif
312                break;
313             case 'd':    /*  directory */
314                if(argv[n][2])
315                  dir = argv[n]+2;
316                else if(++n<argc)
317                  dir = argv[n];
318                else {
319                  fprintf(stderr,"-d: Parameter (directory name) is required\n");
320                  clean_exit(EX_USAGE);
321                }
322                break;
323             case 's':    /*  subject */
324                if(argv[n][2])
325                  tmp = argv[n]+2;
326                else if(++n<argc)
327                  tmp = argv[n];
328                else {
329                  fprintf(stderr,"-s: Parameter (subject) is required\n");
330                  clean_exit(EX_USAGE);
331                }
332                if (strlen(tmp)>72) { /* Max "subject", see FTS-1 */
333                  fprintf(stderr,"-s: Subject line too long, truncated to 72 characters.\n");
334                  tmp[72]='\0';
335                }
336                msg.subjectLine = sstrdup(tmp);
337                tmp=NULL;
338 #ifdef __NT__
339                CharToOem(msg.subjectLine, msg.subjectLine);
340 #endif
341                break;
342             case 'q':    /* quiet mode */
343               quiet_mode = 1;
344                break;
345 	    default:
346                quit = 1;
347                break;
348          }
349          if (quit) {
350             fprintf(stderr,"Unknown option '%s', exit.\n", argv[n]);
351             clean_exit(EX_USAGE);
352          }
353       } else {
354          if (strcmp(argv[n], "-") == 0)
355             text = stdin;
356          else
357             text = fopen(argv[n], "rt");
358 
359          if (text != NULL) {
360             int cursize = TEXTBUFFERSIZE, c;
361             /* reserve 512kb + 1 (or 32kb+1) text Buffer */
362             textBuffer = safe_malloc(cursize);
363             for (msg.textLength = 0;; msg.textLength++) {
364                 if (msg.textLength >= cursize)
365                     textBuffer = safe_realloc(textBuffer, cursize += TEXTBUFFERSIZE);
366                 c = getc(text);
367                 if (c == EOF || c == 0) {
368                     textBuffer[msg.textLength] = 0;
369                     break;
370                 }
371                 textBuffer[msg.textLength] = (char)c;
372                 if ('\r' == textBuffer[msg.textLength])
373                     msg.textLength--;
374                 if ('\n' == textBuffer[msg.textLength])
375                     textBuffer[msg.textLength] = '\r';
376             } /* endfor */
377             while (!feof(text))
378                 getc(text);
379             if (strcmp(argv[n], "-"))
380             fclose(text);
381          } else {
382 	    fprintf(stderr,"Text file not found, exit\n");
383 	    exit(EX_NOINPUT);
384 	 }
385       }
386    }
387 
388    if (!textBuffer) {
389 	    fprintf(stderr,"Text file not specified, exit\n");
390 	    exit(EX_NOINPUT);
391    }
392 
393    config = readConfig(cfgFile);
394    if (NULL == config) {
395       fprintf(stderr,"Config not found, exit\n");
396       exit(EX_UNAVAILABLE);
397    }
398 
399    if (!quiet_mode) printf("%s\n\n", versionStr);
400 
401    header.hiProductCode  = HPT_PRODCODE_HIGHBYTE;
402    header.loProductCode  = HPT_PRODCODE_LOWBYTE;
403    header.majorProductRev = VER_MAJOR;
404    header.minorProductRev = VER_MINOR;
405    if (passwd!=NULL) strcpy(header.pktPassword, passwd);
406    header.pktCreated = time(NULL);
407 
408    header.capabilityWord = 1;
409    header.prodData = 0;
410 
411    if (header.origAddr.zone==0) header.origAddr = msg.origAddr;
412    if (header.destAddr.zone==0) header.destAddr = msg.destAddr;
413 
414 #ifdef __UNIX__
415    xstrcat(&tmp, (dir) ? dir : "./");
416    if (tmp[strlen(tmp)-1] != '/') xstrcat(&tmp,"/");
417 #else
418    xstrcat(&tmp, (dir) ? dir : ".\\");
419    if (tmp[strlen(tmp)-1] != '\\')  xstrcat(&tmp,"\\");
420 #endif
421 
422    /* Make pkt name */
423    if (config->seqDir == NULL) {
424        time_t tm = time(NULL);
425        int pathlen = strlen(tmp);
426        char* tmpp;
427        xscatprintf(&tmp,"%08lx.pkt",(long)tm++);
428        tmpp = tmp+pathlen;
429        pkt = createPkt(tmp, &header);
430        while(pkt==NULL){
431          sprintf(tmpp,"%08lx.pkt",(long)tm++);
432          pkt = createPkt(tmp, &header);
433        }
434        if (!quiet_mode) printf("%s\n", tmp);
435    } else {
436        do {
437            nfree(fileName);
438            xscatprintf(&fileName, "%s%08x.pkt",
439                        tmp, GenMsgId(config->seqDir, config->seqOutrun));
440        } while ((pkt = createPkt(fileName, &header))==NULL);
441        if (!quiet_mode) printf("%s\n", fileName);
442    }
443 
444    if (pkt != NULL) {
445 
446       t = time (NULL);
447       tm = localtime(&t);
448       fts_time((char *)msg.datetime, tm);
449 
450       if (tearl || config->tearline) {
451          *tmp='\0';
452          xscatprintf(&tmp, "\r--- %s\r", (tearl) ? tearl : config->tearline);
453          xstrcat(&textBuffer, tmp);
454       }
455 
456       if (msg.origAddr.zone==0 && msg.origAddr.net==0 &&
457            msg.origAddr.node==0 && msg.origAddr.point==0)
458 	   msg.origAddr = config->addr[0];
459 
460       if (area != NULL) {
461          msg.attributes = 0;
462          msg.netMail = 0;
463          *tmp='\0';
464          strUpper(area);
465          xscatprintf(&tmp, " * Origin: %s (%d:%d/%d.%d)\r",
466                  (orig) ? orig : (config->origin) ? config->origin : "",
467 		 msg.origAddr.zone, msg.origAddr.net,
468                  msg.origAddr.node, msg.origAddr.point);
469          xstrcat(&textBuffer, tmp);
470          *tmp='\0';
471          xscatprintf(&tmp,"SEEN-BY: %d/%d\r\1PATH: %d/%d\r",
472 	         header.origAddr.net,header.origAddr.node,
473 		 header.origAddr.net,header.origAddr.node);
474          xstrcat(&textBuffer, tmp);
475       }
476       else
477       {
478          msg.attributes = 1;
479          msg.netMail = 1;
480       }
481       msg.text = createKludges(config,
482                                area, &msg.origAddr, &msg.destAddr,
483                                versionStr);
484       if (!config->disableTID)
485          xscatprintf(&(msg.text), "\001TID: %s\r", versionStr);
486       xstrcat(&(msg.text), textBuffer);
487       if (area == NULL) {
488          time(&t);
489          tm = gmtime(&t);
490          xscatprintf(&(msg.text), "\001Via %u:%u/%u.%u @%04u%02u%02u.%02u%02u%02u.UTC %s\r",
491                  header.origAddr.zone, header.origAddr.net, header.origAddr.node, header.origAddr.point,
492                  tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, versionStr);
493       }
494 
495       msg.textLength=strlen(textBuffer);
496       nfree(textBuffer);
497       nfree(versionStr);
498 
499       if (msg.fromUserName==NULL) xstrcat(&msg.fromUserName, "Sysop");
500       if (msg.toUserName==NULL)  xstrcat(&msg.toUserName, "All");
501       if (msg.subjectLine==NULL) xstrcat(&msg.subjectLine, "");
502 
503       /*  load recoding tables */
504       initCharsets();
505       getctabs(NULL,config->outtab);
506 
507       if (config->outtab != NULL) {
508          /*  recoding text to TransportCharSet */
509          recodeToTransportCharset((char*)msg.text);
510          recodeToTransportCharset((char*)msg.subjectLine);
511          recodeToTransportCharset((char*)msg.fromUserName);
512          recodeToTransportCharset((char*)msg.toUserName);
513       }
514 
515       writeMsgToPkt(pkt, msg);
516 
517       closeCreatedPkt(pkt);
518 /*      sleep(1); */
519    } else {
520       fprintf(stderr, "Could not create pkt, error message: %s", strerror(errno));
521    } /* endif */
522 
523    doneCharsets();
524    disposeConfig(config);
525 
526    return 0;
527 }
528