1 /*
2  * This file is part of uudeview, the simple and friendly multi-part multi-
3  * file uudecoder  program  (c) 1994-2001 by Frank Pilhofer. The author may
4  * be contacted at fp@fpx.de
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 /*
18  * The TCL Interface of UUDeview
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #if defined(HAVE_TCL) || defined(HAVE_TK)
26 
27 #ifdef SYSTEM_WINDLL
28 #include <windows.h>
29 #endif
30 #ifdef SYSTEM_OS2
31 #include <os2.h>
32 #endif
33 
34 #ifdef STDC_HEADERS
35 #include <stdlib.h>
36 #include <string.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #ifdef HAVE_ERRNO_H
42 #include <errno.h>
43 #endif
44 
45 #ifdef HAVE_TK
46 #include <tk.h>
47 #else
48 #include <tcl.h>
49 #endif
50 
51 /*
52  * The following variable is a special hack that is needed in order for
53  * Sun shared libraries to be used for Tcl.
54  */
55 
56 extern int matherr();
57 int *tclDummyMathPtr = (int *) matherr;
58 
59 #include <uudeview.h>
60 #include <uuint.h>
61 #include <fptools.h>
62 
63 /*
64  * As Windows DLL, we need a DllEntryPoint
65  */
66 
67 #ifdef SYSTEM_WINDLL
68 BOOL _export WINAPI
DllEntryPoint(HINSTANCE hInstance,DWORD seginfo,LPVOID lpCmdLine)69 DllEntryPoint (HINSTANCE hInstance, DWORD seginfo,
70 	       LPVOID lpCmdLine)
71 {
72   /* Don't do anything, so just return true */
73   return TRUE;
74 }
75 #endif
76 
77 /*
78  * Declare external functions as __cdecl for Watcom C
79  */
80 
81 #ifdef __WATCOMC__
82 #pragma aux (__cdecl) Tcl_Eval
83 #pragma aux (__cdecl) Tcl_GetVar
84 #pragma aux (__cdecl) Tcl_SetVar
85 #pragma aux (__cdecl) Tcl_AppendResult
86 #pragma aux (__cdecl) Tcl_SetResult
87 #pragma aux (__cdecl) Tcl_CreateCommand
88 #endif
89 
90 /*
91  * cvs version
92  */
93 char * uutcl_id = "$Id: uutcl.c,v 1.14 2002/03/06 13:52:45 fp Exp $";
94 
95 /*
96  * data for our Callbacks
97  */
98 
99 static struct uutclcbdata {
100   Tcl_Interp *interp;
101   char tclproc[256];
102 } theDMcbdata, theBusycbdata;
103 
104 /*
105  * Don't let Uu_Init initialize us twice
106  */
107 
108 static int uu_AlreadyInitialized = 0;
109 
110 /*
111  * mail and news software
112  */
113 
114 #ifdef PROG_INEWS
115 char *  uue_inewsprog = PROG_INEWS;
116 #else
117 char *  uue_inewsprog = NULL;
118 #endif
119 #ifdef PROG_MAILER
120 char *  uue_mailprog  = PROG_MAILER;
121 #else
122 char *  uue_mailprog  = NULL;
123 #endif
124 #ifdef MAILER_NEEDS_SUBJECT
125 int     uue_mpsubject = 1;
126 #else
127 int     uue_mpsubject = 0;
128 #endif
129 
130 /*
131  * Mail or Post a file. Remember to keep in sync with uuenview.c
132  */
133 
134 static int
SendAFile(Tcl_Interp * interp,FILE * infile,char * infname,int encoding,int linperfile,char * outfname,char * towhom,char * subject,char * from,char * replyto,int isemail)135 SendAFile (Tcl_Interp *interp,
136 	   FILE *infile,   char *infname,
137 	   int encoding,   int linperfile,
138 	   char *outfname, char *towhom,
139 	   char *subject,  char *from,
140 	   char *replyto,  int isemail)
141 {
142   char *command, *rcptlist, *ptr;
143   FILE *thepipe, *theifile;
144   int len, count, res, part;
145 
146   if (towhom==NULL ||
147       (outfname==NULL&&infname==NULL) || (infile&&infname==NULL) ||
148       (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED&&
149        encoding!=PT_ENCODED&&encoding!=QP_ENCODED)) {
150     Tcl_SetResult (interp, "oops: Parameter check failed in SendAFile()",
151 		   TCL_STATIC);
152     return UURET_ILLVAL;
153   }
154 
155 #ifndef HAVE_POPEN
156   Tcl_SetResult (interp, "error: Your system does not support sending of files",
157 		 TCL_STATIC);
158   return UURET_ILLVAL;
159 #else
160   if (isemail && (uue_mailprog == NULL || *uue_mailprog == '\0')) {
161     Tcl_SetResult (interp, "error: Cannot Email file: option not configured",
162 		   TCL_STATIC);
163     return UURET_ILLVAL;
164   }
165   else if (!isemail && (uue_inewsprog == NULL || *uue_inewsprog == '\0')) {
166     Tcl_SetResult (interp, "error: Cannot Post file: option not configured",
167 		   TCL_STATIC);
168     return UURET_ILLVAL;
169   }
170 
171   len = strlen ((isemail)?uue_mailprog:uue_inewsprog) +
172     ((uue_mpsubject)?strlen(subject):0) +
173       ((isemail)?0:strlen(towhom)) + 32;
174 
175   if ((command = (char *) malloc (len)) == NULL) {
176     Tcl_SetResult (interp, "error: Out of memory allocating some bytes",
177 		   TCL_STATIC);
178     return UURET_NOMEM;
179   }
180 
181   if ((rcptlist = (char *) malloc (strlen (towhom) + 16)) == NULL) {
182     Tcl_SetResult (interp, "error: Out of memory allocating some bytes",
183 		   TCL_STATIC);
184     _FP_free (command);
185     return UURET_NOMEM;
186   }
187 
188   if (isemail) {
189     if (uue_mpsubject)
190       sprintf (command, "%s -s \"%s\"", uue_mailprog, subject);
191     else
192       sprintf (command, "%s", uue_mailprog);
193 
194     /*
195      * Attach list of recipients to mailer command and compose another list
196      * of recipients
197      */
198 
199     count = 0;
200     rcptlist[0] = '\0';
201     ptr = _FP_strtok (towhom, ",; ");
202 
203     while (ptr) {
204       strcat (command, " ");
205       strcat (command, ptr);
206 
207       if (count++)
208 	strcat (rcptlist, ",");
209       strcat (rcptlist, ptr);
210 
211       ptr = _FP_strtok (NULL, ",; ");
212     }
213   }
214   else {
215     sprintf (command, "%s", uue_inewsprog);
216 
217     count = 0;
218     rcptlist[0] = '\0';
219     ptr = _FP_strtok (towhom, ";, ");
220 
221     while (ptr) {
222       if (count++)
223 	strcat (rcptlist, ",");
224       strcat (rcptlist, ptr);
225       ptr = _FP_strtok (NULL, ";, ");
226     }
227   }
228 
229   if (from && *from == '\0') {
230     from = NULL;
231   }
232 
233   if (subject && *subject == '\0') {
234     subject = NULL;
235   }
236 
237   if (replyto && *replyto == '\0') {
238     replyto = NULL;
239   }
240 
241   /*
242    * Get going ...
243    */
244 
245   if (infile == NULL) {
246     if ((theifile = fopen (infname, "rb")) == NULL) {
247       _FP_free (rcptlist);
248       _FP_free (command);
249       return UURET_IOERR;
250     }
251   }
252   else {
253     theifile = infile;
254   }
255 
256   for (part=1; !feof (theifile); part++) {
257     if ((thepipe = popen (command, "w")) == NULL) {
258       if (infile==NULL) fclose (theifile);
259       _FP_free (rcptlist);
260       _FP_free (command);
261       return UURET_IOERR;
262     }
263 
264     if (UUGetOption(UUOPT_VERBOSE, NULL, NULL, 0)) {
265 #if 0
266       fprintf (stderr, "%s part %03d of %s to %s ... ",
267 	       (isemail)?"mailing":"posting",
268 	       part, (infname)?infname:outfname,
269 	       rcptlist);
270       fflush  (stderr);
271 #endif
272     }
273 
274     res = UUE_PrepPartialExt (thepipe, theifile, infname, encoding,
275 			      outfname, 0, part, linperfile, 0,
276 			      rcptlist, from, subject, replyto,
277 			      isemail);
278 
279 #if 0
280     if (UUGetOption (UUOPT_VERBOSE, NULL, NULL, 0)) {
281       if (res == UURET_OK)
282 	fprintf (stderr, "ok.\n");
283       else
284 	fprintf (stderr, "%s\n", UUstrerror (res));
285     }
286 #endif
287 
288     pclose (thepipe);
289 
290     if (res != UURET_OK) {
291       if (infile == NULL) fclose (theifile);
292       _FP_free (rcptlist);
293       _FP_free (command);
294       return res;
295     }
296   }
297 
298   if (infile == NULL) fclose (theifile);
299   _FP_free (rcptlist);
300   _FP_free (command);
301   return UURET_OK;
302 #endif
303 }
304 
305 /*
306  * Display a Message in a dialog box
307  */
308 
309 static void
uutcl_DisplayMessage(void * param,char * message,int level)310 uutcl_DisplayMessage (void *param, char *message, int level)
311 {
312   struct uutclcbdata *data = (struct uutclcbdata *) param;
313   char tmpstring[2048];
314 
315   if (data->interp && *data->tclproc) {
316     sprintf  (tmpstring, "%s %d {%s}\n", data->tclproc, level, message);
317     Tcl_Eval (data->interp, tmpstring);
318   }
319 }
320 
321 /*
322  * Our Busy Callback
323  */
324 
325 static int
uutcl_BusyCallback(void * param,uuprogress * progress)326 uutcl_BusyCallback (void *param, uuprogress *progress)
327 {
328   struct uutclcbdata *data = (struct uutclcbdata *) param;
329 
330   if (data->interp && *data->tclproc) {
331     Tcl_Eval (data->interp, data->tclproc);
332   }
333   return 0;
334 }
335 
336 /*
337  * exchage variables with the interpreter
338  */
339 
340 static void
uutcl_UpdateParameter(Tcl_Interp * interp)341 uutcl_UpdateParameter (Tcl_Interp *interp)
342 {
343   char *cval;
344 
345   if ((cval = Tcl_GetVar (interp, "OptionFast",     TCL_GLOBAL_ONLY))!=NULL)
346     UUSetOption (UUOPT_FAST, atoi (cval), NULL);
347   if ((cval = Tcl_GetVar (interp, "OptionBracket",  TCL_GLOBAL_ONLY))!=NULL)
348     UUSetOption (UUOPT_BRACKPOL, atoi (cval), NULL);
349   if ((cval = Tcl_GetVar (interp, "OptionDesperate",TCL_GLOBAL_ONLY))!=NULL)
350     UUSetOption (UUOPT_DESPERATE, atoi (cval), NULL);
351   if ((cval = Tcl_GetVar (interp, "OptionDebug",    TCL_GLOBAL_ONLY))!=NULL)
352     UUSetOption (UUOPT_DEBUG, atoi (cval), NULL);
353   if ((cval = Tcl_GetVar (interp, "OptionDumbness", TCL_GLOBAL_ONLY))!=NULL)
354     UUSetOption (UUOPT_DUMBNESS, atoi (cval), NULL);
355   if ((cval = Tcl_GetVar (interp, "OptionUsetext",  TCL_GLOBAL_ONLY))!=NULL)
356     UUSetOption (UUOPT_USETEXT, atoi (cval), NULL);
357   if ((cval = Tcl_GetVar (interp, "SaveFilePath",   TCL_GLOBAL_ONLY))!=NULL)
358     UUSetOption (UUOPT_SAVEPATH, 0, cval);
359   if ((cval = Tcl_GetVar (interp, "OptionRemove",   TCL_GLOBAL_ONLY))!=NULL)
360     UUSetOption (UUOPT_REMOVE, atoi (cval), NULL);
361   if ((cval = Tcl_GetVar (interp, "OptionMoreMime", TCL_GLOBAL_ONLY))!=NULL)
362     UUSetOption (UUOPT_MOREMIME, atoi (cval), NULL);
363 }
364 
365 /*
366  * configuration info
367  */
368 
369 static int
uutcl_HaveArg(int argc,char * argv[],char * string)370 uutcl_HaveArg (int argc, char *argv[], char *string)
371 {
372   int index;
373 
374   for (index=1; index<argc; index++) {
375     if (_FP_stricmp (argv[index], string) == 0)
376       return 1;
377   }
378   return 0;
379 }
380 
381 static int UUTCLFUNC
uutcl_Info(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])382 uutcl_Info (ClientData clientData, Tcl_Interp *interp,
383 	    int argc, char *argv[])
384 {
385   char temp[64], version[64];
386 
387   if (argc==1 || uutcl_HaveArg (argc, argv, "version")) {
388     UUGetOption (UUOPT_VERSION, NULL, version, 64);
389     sprintf (temp, " { version %s } ", version);
390     Tcl_AppendResult (interp, temp, NULL);
391   }
392   if (argc==1 || uutcl_HaveArg (argc, argv, "have_tcl"))
393 #ifdef HAVE_TCL
394     Tcl_AppendResult (interp, " { have_tcl 1 } ", NULL);
395 #else
396     Tcl_AppendResult (interp, " { have_tcl 0 } ", NULL);
397 #endif
398   if (argc==1 || uutcl_HaveArg (argc, argv, "have_tk"))
399 #ifdef HAVE_TK
400     Tcl_AppendResult (interp, " { have_tk 1 } ", NULL);
401 #else
402     Tcl_AppendResult (interp, " { have_tk 0 } ", NULL);
403 #endif
404   if (argc==1 || uutcl_HaveArg (argc, argv, "have_mail")) {
405 #ifdef PROG_MAILER
406     if (*PROG_MAILER)
407       Tcl_AppendResult (interp, " { have_mail 1 } ", NULL);
408     else
409       Tcl_AppendResult (interp, " { have_mail 0 } ", NULL);
410 #else
411     Tcl_AppendResult (interp, " { have_mail 0 } ", NULL);
412 #endif
413   }
414   if (argc==1 || uutcl_HaveArg (argc, argv, "prog_mailer")) {
415 #ifdef PROG_MAILER
416     sprintf (temp, " { prog_mailer \"%s\" } ", PROG_MAILER);
417     Tcl_AppendResult (interp, temp, NULL);
418 #else
419     Tcl_AppendResult (interp, " { prog_mailer (none) } ", NULL);
420 #endif
421   }
422   if (argc==1 || uutcl_HaveArg (argc, argv, "have_news")) {
423 #ifdef HAVE_NEWS
424     Tcl_AppendResult (interp, " { have_news 1 } ", NULL);
425 #else
426     Tcl_AppendResult (interp, " { have_news 0 } ", NULL);
427 #endif
428   }
429   if (argc==1 || uutcl_HaveArg (argc, argv, "prog_inews")) {
430 #ifdef PROG_INEWS
431     sprintf (temp, " { prog_inews \"%s\" } ", PROG_INEWS);
432     Tcl_AppendResult (interp, temp, NULL);
433 #else
434     Tcl_AppendResult (interp, " { prog_inews (none) } ", NULL);
435 #endif
436   }
437   if (argc==1 || uutcl_HaveArg (argc, argv, "domainname")) {
438 #ifdef DOMAINNAME
439     sprintf (temp, " { domainname %s } ", DOMAINNAME);
440     Tcl_AppendResult (interp, temp, NULL);
441 #else
442     Tcl_AppendResult (interp, " { domainname (none) } ", NULL);
443 #endif
444   }
445   if (argc==1 || uutcl_HaveArg (argc, argv, "nntpserver")) {
446 #ifdef NNTPSERVER
447     sprintf (temp, " { nntpserver %s } ", NNTPSERVER);
448     Tcl_AppendResult (interp, temp, NULL);
449 #else
450     Tcl_AppendResult (interp, " { nntpserver (none) } ", NULL);
451 #endif
452   }
453   if (argc==1 || uutcl_HaveArg (argc, argv, "need_nntpserver")) {
454 #ifdef NEED_NNTPSERVER
455     Tcl_AppendResult (interp, " { need_nntpserver 1 } ", NULL);
456 #else
457     Tcl_AppendResult (interp, " { need_nntpserver 0 } ", NULL);
458 #endif
459   }
460   return TCL_OK;
461 }
462 
463 static int UUTCLFUNC
uutcl_SetMessageProc(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])464 uutcl_SetMessageProc (ClientData clientData, Tcl_Interp *interp,
465 		      int argc, char *argv[])
466 {
467   char tmpstring[256];
468 
469   uutcl_UpdateParameter (interp);
470 
471   if (argc != 2) {
472     sprintf (tmpstring,
473 	     "wrong # args: should be \"%s procedure\"",
474 	     argv[0]);
475     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
476     return TCL_ERROR;
477   }
478 
479   theDMcbdata.interp = interp;
480   strcpy (theDMcbdata.tclproc, argv[1]);
481   return TCL_OK;
482 }
483 
484 static int UUTCLFUNC
uutcl_SetBusyProc(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])485 uutcl_SetBusyProc (ClientData clientData, Tcl_Interp *interp,
486 		   int argc, char *argv[])
487 {
488   char tmpstring[256];
489   long msecs;
490 
491   uutcl_UpdateParameter (interp);
492 
493   if (argc != 3) {
494     sprintf (tmpstring,
495 	     "wrong # args: should be \"%s procedure msecs\"",
496 	     argv[0]);
497     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
498     return TCL_ERROR;
499   }
500 
501   if ((msecs = (long) atoi (argv[2])) > 0) {
502     UUSetBusyCallback (&theBusycbdata, uutcl_BusyCallback, msecs);
503   }
504 
505   theBusycbdata.interp = interp;
506   strcpy (theBusycbdata.tclproc, argv[1]);
507   return TCL_OK;
508 }
509 
510 static int UUTCLFUNC
uutcl_GetProgressInfo(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])511 uutcl_GetProgressInfo (ClientData clientData, Tcl_Interp *interp,
512 		       int argc, char *argv[])
513 {
514   uuprogress progress;
515   char tmpstring[32];
516 
517   if (UUGetOption (UUOPT_PROGRESS, NULL,
518 		   (char *) &progress, sizeof (uuprogress)) != 0) {
519     Tcl_SetResult (interp, "oops, could not get info?", TCL_STATIC);
520     return TCL_ERROR;
521   }
522   sprintf (tmpstring, "%d", progress.action);
523   Tcl_AppendElement (interp, tmpstring);
524 
525   Tcl_AppendElement (interp, progress.curfile);
526 
527   sprintf (tmpstring, "%d", progress.partno);
528   Tcl_AppendElement (interp, tmpstring);
529 
530   sprintf (tmpstring, "%d", progress.numparts);
531   Tcl_AppendElement (interp, tmpstring);
532 
533   sprintf (tmpstring, "%d", progress.percent);
534   Tcl_AppendElement (interp, tmpstring);
535 
536   return TCL_OK;
537 }
538 
539 static int UUTCLFUNC
uutcl_GetListOfFiles(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])540 uutcl_GetListOfFiles (ClientData clientData, Tcl_Interp *interp,
541 		      int argc, char *argv[])
542 {
543   char tmpstring[1024], t2[42];
544   int count=0, index=0;
545   uulist *iter;
546 
547   uutcl_UpdateParameter (interp);
548 
549   while ((iter=UUGetFileListItem(count))) {
550     if (((iter->state & UUFILE_OK) ||
551 	 UUGetOption (UUOPT_DESPERATE, NULL, NULL, 0)) && iter->filename) {
552       sprintf (tmpstring, " { %d %d {%s} %s %s {",
553 	       count, iter->state, iter->filename,
554 	       (iter->mimetype)?iter->mimetype:"{}",
555 	       (iter->uudet == UU_ENCODED) ? "UUdata " :
556 	       (iter->uudet == B64ENCODED) ? "Base64 " :
557 	       (iter->uudet == XX_ENCODED) ? "XXdata " :
558 	       (iter->uudet == BH_ENCODED) ? "Binhex " :
559 	       (iter->uudet == YENC_ENCODED) ? "yEnc" : "Text");
560 
561       if (iter->haveparts) {
562 	sprintf (t2, "%s%s%d ",
563 		 (iter->begin&&iter->begin==iter->haveparts[0])?"begin ":"",
564 		 (iter->end  &&iter->end == iter->haveparts[0])?"end "  :"",
565 		 iter->haveparts[0]);
566 	strcat (tmpstring, t2);
567 
568 	for (index=1; iter->haveparts[index]; index++) {
569 	  sprintf (t2, "%s%s%d ",
570 		   (iter->begin==iter->haveparts[index]) ? "begin " : "",
571 		   (iter->end == iter->haveparts[index]) ? "end " : "",
572 		   iter->haveparts[index]);
573 	  strcat (tmpstring, t2);
574 	}
575       }
576 
577       if (iter->state & UUFILE_OK)
578 	strcat (tmpstring, "OK");
579 
580       strcat (tmpstring, "} }");
581 
582       Tcl_AppendResult (interp, tmpstring, NULL);
583     }
584     count++;
585   }
586 
587   return TCL_OK;
588 }
589 
590 /*
591  * Load an encoded file
592  */
593 
594 static int UUTCLFUNC
uutcl_LoadFile(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])595 uutcl_LoadFile (ClientData clientData, Tcl_Interp *interp,
596 		int argc, char *argv[])
597 {
598   char tmpstring[256];
599   int res;
600 
601   uutcl_UpdateParameter (interp);
602 
603   if (argc != 2) {
604     sprintf (tmpstring,
605 	     "wrong # args: should be \"%s filename\"",
606 	     argv[0]);
607     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
608     return TCL_ERROR;
609   }
610 
611   if ((res = UULoadFile (argv[1], NULL, 0)) != UURET_OK) {
612     sprintf (tmpstring, "couldn't read %s: %s (%s)",
613 	     argv[1], UUstrerror (res),
614 	     (res==UURET_IOERR)?
615 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
616     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
617     return TCL_ERROR;
618   }
619 
620   return TCL_OK;
621 }
622 
623 /*
624  * Decode A File. This function overwrites files without asking, because
625  * this was already done by the script
626  */
627 
628 static int UUTCLFUNC
uutcl_DecodeFile(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])629 uutcl_DecodeFile (ClientData clientData, Tcl_Interp *interp,
630 		  int argc, char *argv[])
631 {
632   char tmpstring[256];
633   uulist *iter;
634   int res;
635 
636   uutcl_UpdateParameter (interp);
637 
638   if (argc < 2 || argc > 3) {
639     sprintf (tmpstring,
640 	     "wrong # args: should be \"%s number ?targetname?\"",
641 	     argv[0]);
642     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
643     return TCL_ERROR;
644   }
645 
646   if ((iter = UUGetFileListItem (atoi (argv[1]))) == NULL) {
647     Tcl_SetResult (interp, "invalid file number", TCL_STATIC);
648     return TCL_ERROR;
649   }
650 
651   if ((res = UUDecodeFile (iter, (argc==3)?argv[2]:NULL)) != UURET_OK) {
652     sprintf (tmpstring, "Error while decoding %s (%s): %s (%s)",
653 	     (iter->filename) ? iter->filename : "",
654 	     (iter->subfname) ? iter->subfname : "",
655 	     UUstrerror (res),
656 	     (res==UURET_IOERR)?
657 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
658     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
659     return TCL_ERROR;
660   }
661 
662   return TCL_OK;
663 }
664 
665 static int UUTCLFUNC
uutcl_GetTempFile(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])666 uutcl_GetTempFile (ClientData clientData, Tcl_Interp *interp,
667 		   int argc, char *argv[])
668 {
669   char tmpstring[256];
670   uulist *iter;
671   int res;
672 
673   uutcl_UpdateParameter (interp);
674 
675   if (argc != 2) {
676     sprintf (tmpstring,
677 	     "wrong # args: should be \"%s number\"",
678 	     argv[0]);
679     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
680     return TCL_ERROR;
681   }
682 
683   if ((iter = UUGetFileListItem (atoi (argv[1]))) == NULL) {
684     Tcl_SetResult (interp, "invalid file number", TCL_STATIC);
685     return TCL_ERROR;
686   }
687 
688   if ((res = UUDecodeToTemp (iter)) != UURET_OK) {
689     sprintf (tmpstring, "Error while decoding %s (%s): %s (%s)",
690 	     (iter->filename) ? iter->filename : "",
691 	     (iter->subfname) ? iter->subfname : "",
692 	     UUstrerror (res),
693 	     (res==UURET_IOERR)?
694 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
695     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
696     return TCL_ERROR;
697   }
698 
699   if (iter->binfile == NULL) {
700     Tcl_SetResult (interp, "unknown error while decoding", TCL_STATIC);
701     return TCL_ERROR;
702   }
703 
704   Tcl_SetResult (interp, iter->binfile, TCL_VOLATILE);
705   return TCL_OK;
706 }
707 
708 /*
709  * InfoFile takes two parameters: the number of the file to get info for,
710  * and the name of the text widget to send the text to
711  */
712 
713 struct uuInfoCBData {
714   Tcl_Interp *interp;
715   char *      widget;
716 };
717 
718 static int
uutcl_InfoCallback(void * param,char * string)719 uutcl_InfoCallback (void *param, char *string)
720 {
721   struct uuInfoCBData *data = (struct uuInfoCBData *) param;
722   char tmpstring[1024], *p;
723 
724   sprintf (tmpstring, "%s insert end \"", data->widget);
725 
726   p = tmpstring + strlen (tmpstring);
727 
728   while (*string) {
729     switch (*string) {
730     case '"':
731     case '\\':
732     case '[':
733     case ']':
734     case '$':
735       *p++ = '\\';
736       /* fallthrough */
737     default:
738       *p++ = *string;
739     }
740     string++;
741   }
742   *p++ = '"';
743   *p++ = '\0';
744 
745   if (Tcl_Eval (data->interp, tmpstring) != TCL_OK)
746     return 1;
747 
748   return 0;
749 }
750 
751 static int UUTCLFUNC
uutcl_InfoFile(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])752 uutcl_InfoFile (ClientData clientData, Tcl_Interp *interp,
753 		int argc, char *argv[])
754 {
755   struct uuInfoCBData data;
756   char tmpstring[256];
757   uulist *iter;
758   int res;
759 
760   uutcl_UpdateParameter (interp);
761 
762   if (argc != 3) {
763     sprintf (tmpstring,
764 	     "wrong # args: should be \"%s number textwidget\"",
765 	     argv[0]);
766     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
767     return TCL_ERROR;
768   }
769 
770   if ((iter = UUGetFileListItem (atoi (argv[1]))) == NULL) {
771     Tcl_SetResult (interp, "invalid file number", TCL_STATIC);
772     return TCL_ERROR;
773   }
774 
775   sprintf  (tmpstring, "%s delete 1.0 end", argv[2]);
776   if (Tcl_Eval (interp, tmpstring) != TCL_OK)
777     return TCL_ERROR;
778 
779   data.interp = interp;
780   data.widget = argv[2];
781 
782   if ((res = UUInfoFile (iter, &data, uutcl_InfoCallback)) != UURET_OK) {
783     sprintf (tmpstring, "Error while getting info for %s (%s): %s (%s)",
784 	     (iter->filename) ? iter->filename : "",
785 	     (iter->subfname) ? iter->subfname : "",
786 	     UUstrerror (res),
787 	     (res==UURET_IOERR)?
788 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
789     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
790     return TCL_ERROR;
791   }
792 
793   return TCL_OK;
794 }
795 
796 /*
797  * ShowFile takes two parameters: the number of the file to get info for,
798  * and the name of the text widget to send the text to. We might have to
799  * decode the file before we can show it.
800  * Hey, the above callback worked so well, let's use it again!
801  */
802 
803 static int UUTCLFUNC
uutcl_ListFile(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])804 uutcl_ListFile (ClientData clientData, Tcl_Interp *interp,
805 		int argc, char *argv[])
806 {
807   uulist *iter;
808   struct uuInfoCBData data;
809   char tmpstring[1024];
810   FILE *inpfile;
811   int res;
812 
813   uutcl_UpdateParameter (interp);
814 
815   if (argc != 3) {
816     sprintf (tmpstring,
817 	     "wrong # args: should be \"%s number textwidget\"",
818 	     argv[0]);
819     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
820     return TCL_ERROR;
821   }
822 
823   if ((iter = UUGetFileListItem (atoi (argv[1]))) == NULL) {
824     Tcl_SetResult (interp, "invalid file number", TCL_STATIC);
825     return TCL_ERROR;
826   }
827 
828   if ((res = UUDecodeToTemp (iter)) != UURET_OK) {
829     sprintf (tmpstring, "Error while decoding %s (%s): %s (%s)",
830 	     (iter->filename) ? iter->filename : "",
831 	     (iter->subfname) ? iter->subfname : "",
832 	     UUstrerror(res),
833 	     (res==UURET_IOERR)?
834 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
835     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
836     return TCL_ERROR;
837   }
838 
839   sprintf  (tmpstring, "%s delete 1.0 end", argv[2]);
840   if (Tcl_Eval (interp, tmpstring) != TCL_OK)
841     return TCL_ERROR;
842 
843   if (iter->binfile==NULL || (inpfile=fopen (iter->binfile, "r"))==NULL) {
844     Tcl_SetResult (interp, "couldn't read file", TCL_STATIC);
845     return TCL_ERROR;
846   }
847   if ((inpfile = fopen (iter->binfile, "r")) == NULL) {
848     sprintf (tmpstring, "Could not open temp file %s of %s (%s): %s",
849 	     iter->binfile,
850 	     (iter->filename) ? iter->filename : "",
851 	     (iter->subfname) ? iter->subfname : "",
852 	     strerror (errno));
853     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
854     return TCL_ERROR;
855   }
856 
857   data.interp = interp;
858   data.widget = argv[2];
859 
860   while (!feof (inpfile)) {
861     if (_FP_fgets (tmpstring, 512, inpfile) == NULL)
862       break;
863 
864     if (ferror (inpfile))
865       break;
866 
867     if (uutcl_InfoCallback (&data, tmpstring))
868       break;
869   }
870 
871   if (ferror (inpfile)) {
872     sprintf (tmpstring, "Error while reading from temp file %s of %s (%s): %s",
873 	     iter->binfile,
874 	     (iter->filename) ? iter->filename : "",
875 	     (iter->subfname) ? iter->subfname : "",
876 	     strerror (errno));
877     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
878     fclose (inpfile);
879     return TCL_ERROR;
880   }
881 
882   fclose (inpfile);
883   return TCL_OK;
884 }
885 
886 static int UUTCLFUNC
uutcl_Rename(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])887 uutcl_Rename (ClientData clientData, Tcl_Interp *interp,
888 	      int argc, char *argv[])
889 {
890   char tmpstring[256];
891   uulist *iter;
892   int res;
893 
894   uutcl_UpdateParameter (interp);
895 
896   if (argc != 3) {
897     sprintf (tmpstring,
898 	     "wrong # args: should be \"%s number newname\"",
899 	     argv[0]);
900     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
901     return TCL_ERROR;
902   }
903 
904   if (*argv[2] == '\0') {
905     Tcl_SetResult (interp, "illegal file name", TCL_STATIC);
906     return TCL_ERROR;
907   }
908 
909   if ((iter = UUGetFileListItem (atoi (argv[1]))) == NULL) {
910     Tcl_SetResult (interp, "invalid file number", TCL_STATIC);
911     return TCL_ERROR;
912   }
913 
914   if ((res = UURenameFile (iter, argv[2])) != UURET_OK) {
915     sprintf (tmpstring,
916 	     "could not rename %s to %s: %s (%s)",
917 	     (iter->filename) ? iter->filename : "",
918 	     argv[2], UUstrerror (res),
919 	     (res==UURET_IOERR)?
920 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
921     Tcl_SetResult (interp, tmpstring, TCL_VOLATILE);
922     return TCL_ERROR;
923   }
924 
925   return TCL_OK;
926 }
927 
928 /*
929  * clean up memory and temp files
930  */
931 
932 static int UUTCLFUNC
uutcl_CleanUp(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])933 uutcl_CleanUp (ClientData clientData, Tcl_Interp *interp,
934 	       int argc, char *argv[])
935 {
936   uutcl_UpdateParameter (interp);
937 
938   UUCleanUp ();
939 
940   return TCL_OK;
941 }
942 
943 /*
944  * Generic function to extract the encoding and linperfile parameters
945  * from the command's command line
946  */
947 
948 static int
uutcl_GetEncodeParams(Tcl_Interp * interp,int argc,char * argv[],int argv1,int * encoding,int argv2,int * linperfile)949 uutcl_GetEncodeParams (Tcl_Interp *interp,
950 		       int argc,  char *argv[],
951 		       int argv1, int *encoding,
952 		       int argv2, int *linperfile)
953 {
954   if (argv2 && argv2 < argc) {
955     *linperfile = atoi (argv[argv2]);
956 
957     if (*linperfile != 0 && *linperfile < 200) {
958       Tcl_SetResult (interp, "illegal number of lines per file", TCL_STATIC);
959       return TCL_ERROR;
960     }
961   }
962   if (argv1 && argv1 < argc) {
963     switch (*argv[argv1]) {
964     case '0':
965     case 'u':
966     case 'U':
967       *encoding = UU_ENCODED;
968       break;
969     case '1':
970     case 'x':
971     case 'X':
972       *encoding = XX_ENCODED;
973       break;
974     case '2':
975     case 'b':
976     case 'B':
977       *encoding = B64ENCODED;
978       break;
979     case '3':
980     case 't':
981     case 'T':
982       *encoding = PT_ENCODED;
983       break;
984     case '4':
985     case 'q':
986     case 'Q':
987       *encoding = QP_ENCODED;
988       break;
989     case '5':
990     case 'y':
991     case 'Y':
992       *encoding = YENC_ENCODED;
993       break;
994     default:
995       Tcl_SetResult (interp, "invalid encoding method", TCL_STATIC);
996       return TCL_ERROR;
997     }
998   }
999   return TCL_OK;
1000 }
1001 
1002 /*
1003  * Encode and store in a file.
1004  * Syntax:
1005  *    uu_EncodeToFile source path \
1006  *                    [ dest subject intro lines encoding from replyto]
1007  *
1008  * Most arguments are just for compatibilty with the other encoding procs.
1009  */
1010 
1011 static int UUTCLFUNC
uutcl_EncodeToFile(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])1012 uutcl_EncodeToFile (ClientData clientData, Tcl_Interp *interp,
1013 		    int argc, char *argv[])
1014 {
1015   int encoding=UU_ENCODED, linperfile=0, res;
1016   char errstring[256], olddir[256];
1017 
1018   if (argc < 3 || argc > 10) {
1019     Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
1020     return TCL_ERROR;
1021   }
1022 
1023   uutcl_UpdateParameter (interp);
1024 
1025   if (uutcl_GetEncodeParams (interp, argc, argv,
1026 			     7, &encoding,
1027 			     6, &linperfile) != TCL_OK)
1028     return TCL_ERROR;
1029 
1030   UUGetOption (UUOPT_SAVEPATH, NULL, olddir, 256);
1031   UUSetOption (UUOPT_SAVEPATH, 0, argv[2]);
1032 
1033   if ((res = UUEncodeToFile (NULL, argv[1], encoding,
1034 			     (argc>3) ? argv[3] : NULL,
1035 			     (argc>2) ? argv[2] : NULL,
1036 			     linperfile)) != UURET_OK) {
1037     UUSetOption (UUOPT_SAVEPATH, 0, olddir);
1038     sprintf (errstring, "error while encoding %s to file: %s (%s)", argv[1],
1039 	     UUstrerror(res),
1040 	     (res==UURET_IOERR)?
1041 	     strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
1042     Tcl_SetResult (interp, errstring, TCL_VOLATILE);
1043     return TCL_ERROR;
1044   }
1045   UUSetOption (UUOPT_SAVEPATH, 0, olddir);
1046   return TCL_OK;
1047 }
1048 
1049 /*
1050  * Encode and send by email
1051  * Syntax:
1052  *    uu_EncodeToMail source addr \
1053  *                    [ dest subject intro lines encoding from replyto ]
1054  *
1055  * addr can be a single address or a list of addresses
1056  */
1057 
1058 static int UUTCLFUNC
uutcl_EncodeToMail(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])1059 uutcl_EncodeToMail (ClientData clientData, Tcl_Interp *interp,
1060 		    int argc, char *argv[])
1061 {
1062   int encoding=UU_ENCODED, linperfile=0, res;
1063   char errstring[256];
1064 
1065   if (argc < 3 || argc > 10) {
1066     Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
1067     return TCL_ERROR;
1068   }
1069   uutcl_UpdateParameter (interp);
1070 
1071   if (uutcl_GetEncodeParams (interp, argc, argv,
1072 			     7, &encoding,
1073 			     6, &linperfile) != TCL_OK)
1074     return TCL_ERROR;
1075 
1076   if ((res = SendAFile (interp, NULL, argv[1], encoding, linperfile,
1077 			/* outfname */ (argc>3) ? argv[3] : NULL,
1078 			/* towhom   */ argv[2],
1079 			/* subject  */ (argc>4) ? argv[4] : NULL,
1080 			/* from     */ (argc>8) ? argv[8] : NULL,
1081 			/* replyto  */ (argc>9) ? argv[9] : NULL,
1082 			1)) != UURET_OK) {
1083     /*
1084      * If res==UURET_ILLVAL, SendAMail has already filled in the result
1085      */
1086     if (res != UURET_ILLVAL) {
1087       sprintf (errstring, "error while emailing %s: %s (%s)", argv[1],
1088 	       UUstrerror(res),
1089 	       (res==UURET_IOERR)?
1090 	       strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
1091       Tcl_SetResult (interp, errstring, TCL_VOLATILE);
1092     }
1093     return TCL_ERROR;
1094   }
1095   return TCL_OK;
1096 }
1097 
1098 /*
1099  * Encode and post to the news
1100  * Syntax:
1101  *    uu_EncodeToNews source addr \
1102  *                    [ dest subject intro lines encoding from replyto ]
1103  *
1104  * addr can be a single newsgroup or a list of newsgroups
1105  */
1106 
1107 static int UUTCLFUNC
uutcl_EncodeToNews(ClientData clientData,Tcl_Interp * interp,int argc,char * argv[])1108 uutcl_EncodeToNews (ClientData clientData, Tcl_Interp *interp,
1109 		    int argc, char *argv[])
1110 {
1111   int encoding=UU_ENCODED, linperfile=0, res;
1112   char errstring[256];
1113 
1114   if (argc < 3 || argc > 10) {
1115     Tcl_SetResult (interp, "wrong # args", TCL_STATIC);
1116     return TCL_ERROR;
1117   }
1118   uutcl_UpdateParameter (interp);
1119 
1120   if (uutcl_GetEncodeParams (interp, argc, argv,
1121 			     7, &encoding,
1122 			     6, &linperfile) != TCL_OK)
1123     return TCL_ERROR;
1124 
1125   if ((res = SendAFile (interp, NULL, argv[1], encoding, linperfile,
1126 			/* outfname */ (argc>3) ? argv[3] : NULL,
1127 			/* towhom   */ argv[2],
1128 			/* subject  */ (argc>4) ? argv[4] : NULL,
1129 			/* from     */ (argc>8) ? argv[8] : NULL,
1130 			/* replyto  */ (argc>9) ? argv[9] : NULL,
1131 			0)) != UURET_OK) {
1132     /*
1133      * If res==UURET_ILLVAL, SendAMail has already filled in the result
1134      */
1135     if (res != UURET_ILLVAL) {
1136       sprintf (errstring, "error while posting %s: %s (%s)", argv[1],
1137 	       UUstrerror(res),
1138 	       (res==UURET_IOERR)?
1139 	       strerror(UUGetOption(UUOPT_ERRNO,NULL,NULL,0)):"");
1140       Tcl_SetResult (interp, errstring, TCL_VOLATILE);
1141     }
1142     return TCL_ERROR;
1143   }
1144   return TCL_OK;
1145 }
1146 
1147 /*
1148  * Initialize the TCL package. The only function that is exported from
1149  * this module.
1150  */
1151 
1152 int UUTCLEXPORT UUTCLFUNC
Uu_Init(Tcl_Interp * interp)1153 Uu_Init (Tcl_Interp *interp)
1154 {
1155   char tmp[32];
1156 
1157   /*
1158    * Check whether we are already initialized
1159    */
1160 
1161   if (uu_AlreadyInitialized++)
1162     return TCL_OK;
1163 
1164   /*
1165    * Initialize decoding engine
1166    */
1167 
1168   if (UUInitialize () != UURET_OK) {
1169     Tcl_SetResult (interp, "Error initializing decoding engine", TCL_STATIC);
1170     return TCL_ERROR;
1171   }
1172 
1173   /*
1174    * register commands
1175    */
1176 
1177   Tcl_CreateCommand (interp, "uu_Info",          uutcl_Info, NULL, NULL);
1178   Tcl_CreateCommand (interp, "uu_SetMessageProc",uutcl_SetMessageProc,
1179 		     NULL, NULL);
1180   Tcl_CreateCommand (interp, "uu_SetBusyProc",   uutcl_SetBusyProc,NULL,NULL);
1181   Tcl_CreateCommand (interp, "uu_GetProgressInfo",uutcl_GetProgressInfo,
1182 		     NULL, NULL);
1183   Tcl_CreateCommand (interp, "uu_GetListOfFiles",uutcl_GetListOfFiles,
1184 		     NULL, NULL);
1185   Tcl_CreateCommand (interp, "uu_LoadFile",      uutcl_LoadFile, NULL, NULL);
1186   Tcl_CreateCommand (interp, "uu_DecodeFile",    uutcl_DecodeFile, NULL, NULL);
1187   Tcl_CreateCommand (interp, "uu_GetTempFile",   uutcl_GetTempFile,NULL,NULL);
1188   Tcl_CreateCommand (interp, "uu_InfoFile",      uutcl_InfoFile, NULL, NULL);
1189   Tcl_CreateCommand (interp, "uu_ListFile",      uutcl_ListFile, NULL, NULL);
1190   Tcl_CreateCommand (interp, "uu_Rename",        uutcl_Rename, NULL, NULL);
1191   Tcl_CreateCommand (interp, "uu_CleanUp",       uutcl_CleanUp, NULL, NULL);
1192   Tcl_CreateCommand (interp, "uu_EncodeToFile",  uutcl_EncodeToFile,NULL,NULL);
1193   Tcl_CreateCommand (interp, "uu_EncodeToMail",  uutcl_EncodeToMail,NULL,NULL);
1194   Tcl_CreateCommand (interp, "uu_EncodeToNews",  uutcl_EncodeToNews,NULL,NULL);
1195 
1196   /*
1197    * our message-handling function and busy callback
1198    */
1199 
1200   theDMcbdata.interp       = NULL;
1201   theDMcbdata.tclproc[0]   = '\0';
1202   UUSetMsgCallback (&theDMcbdata, uutcl_DisplayMessage);
1203 
1204   theBusycbdata.interp     = NULL;
1205   theBusycbdata.tclproc[0] = '\0';
1206   UUSetBusyCallback (&theBusycbdata, uutcl_BusyCallback, 1000);
1207 
1208   /*
1209    * only set variables if they aren't set already
1210    */
1211 
1212   sprintf (tmp, "%d", UUGetOption (UUOPT_FAST, NULL, NULL, 0));
1213   if (Tcl_GetVar (interp, "OptionFast", TCL_GLOBAL_ONLY) == NULL)
1214     Tcl_SetVar (interp, "OptionFast", tmp, TCL_GLOBAL_ONLY);
1215 
1216   sprintf (tmp, "%d", UUGetOption (UUOPT_BRACKPOL, NULL, NULL, 0));
1217   if (Tcl_GetVar (interp, "OptionBracket", TCL_GLOBAL_ONLY) == NULL)
1218     Tcl_SetVar (interp, "OptionBracket", tmp, TCL_GLOBAL_ONLY);
1219 
1220   sprintf (tmp, "%d", UUGetOption (UUOPT_DESPERATE, NULL, NULL, 0));
1221   if (Tcl_GetVar (interp, "OptionDesperate", TCL_GLOBAL_ONLY) == NULL)
1222     Tcl_SetVar (interp, "OptionDesperate", tmp, TCL_GLOBAL_ONLY);
1223 
1224   sprintf (tmp, "%d", UUGetOption (UUOPT_DEBUG, NULL, NULL, 0));
1225   if (Tcl_GetVar (interp, "OptionDebug", TCL_GLOBAL_ONLY) == NULL)
1226     Tcl_SetVar (interp, "OptionDebug", tmp, TCL_GLOBAL_ONLY);
1227 
1228   sprintf (tmp, "%d", UUGetOption (UUOPT_USETEXT, NULL, NULL, 0));
1229   if (Tcl_GetVar (interp, "OptionUsetext", TCL_GLOBAL_ONLY) == NULL)
1230     Tcl_SetVar (interp, "OptionUsetext", tmp, TCL_GLOBAL_ONLY);
1231 
1232   return TCL_OK;
1233 }
1234 
1235 #endif
1236