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