1 /*****************************************************************************
2  * HPUCODE --- Uuencoded files from FTN messagebase extractor
3  *****************************************************************************
4  * Copyright (C) 2002  Max Chernogor & Husky Team
5  *
6  * http://husky.sf.net
7  *
8  * This file is part of HUSKY fidonet package.
9  *
10  * HUSKY is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2, or (at your option) any
13  * later version.
14  *
15  * HUSKY is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with HPT; see the file COPYING.  If not, write to the Free
22  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *****************************************************************************/
24 /* $Id$ */
25 
26 #include "uuecode.h"
27 #include "dupe.h"
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <huskylib/huskylib.h>
31 
32 
33 static char *invalidExt[] = {"*.mo?", "*.tu?", "*.we?", "*.th?", "*.fr?",
34                                    "*.sa?", "*.su?", "*.pkt", "*.tic"};
35 
36 
37 int  isReady(UUEFile* uuc);
38 void MakeFile(UUEFile* uuc);
39 void MakeTicFile(UUEFile* uuc);
40 
41 typedef struct  {
42     char* areamask;
43     char* fileEcho;
44 }   uueFileGroup;
45 
46 unsigned int fileGroupscount = 0;
47 uueFileGroup *uueFileGroups  = NULL;
48 
initFileGroups()49 void initFileGroups()
50 {
51     unsigned int i = 0;
52 	char *tok;
53 
54     if(!config->numuuEGrp || uueFileGroups)
55         return;
56     for(i = 0; i < config->numuuEGrp; i++)
57     {
58         tok = strtok(config->uuEGrp[i], " \t,");
59         tok = strtok(NULL, " \t,");
60         while (tok) {
61             uueFileGroups = srealloc(uueFileGroups, sizeof(uueFileGroup)*(fileGroupscount+1));
62             uueFileGroups[fileGroupscount].areamask = sstrdup(tok);
63             uueFileGroups[fileGroupscount].fileEcho = config->uuEGrp[i];
64             fileGroupscount++;
65             tok = strtok(NULL, " \t,");
66         }
67     }
68 }
69 
findFileGroup(char * areaMask)70 char* findFileGroup(char* areaMask)
71 {
72     unsigned int i = 0;
73     char* areagroup = NULL;
74     initFileGroups();
75 
76     if(!uueFileGroups)
77         return xstrscat(&areagroup,"uue.",areaMask,NULL);
78     for(i = 0; i < fileGroupscount; i++) {
79         if (patimat(areaMask,uueFileGroups[i].areamask))
80             return sstrdup(uueFileGroups[i].fileEcho);
81     }
82     return xstrscat(&areagroup,"uue.",areaMask,NULL);
83 }
84 
DecodePart(char * text,FILE * outfile)85 int DecodePart(char *text, FILE *outfile)
86 {
87     char *linep	= NULL;
88 
89     size_t   linelen	= 0;
90     int      linecnt	= 0;
91     UCHAR outbyte	[3];
92     char* endl =NULL;
93     char* linebuf = text;
94     int lastlen = 0;
95     int nRet = 0;
96 
97     if(!text) return 0;
98     do
99     {
100         endl = strchr(linebuf,'\r');
101 
102         if(endl) endl[0] = '\0';
103         else     break;
104 
105         /* The first byte of the line represents the length of the DECODED
106         line */
107         linelen = DECODE_BYTE (linebuf [0]);
108         linep = linebuf + 1;
109         for (linecnt = linelen; linecnt > 0; linecnt -= 3, linep += 4)
110         {
111             lastlen = strlen(linep);
112             if(lastlen > 3)
113             {
114                 /* Decode the 4-byte block */
115                 outbyte [0] = DECODE_BYTE (linep [0]);
116                 outbyte [1] = DECODE_BYTE (linep [1]);
117                 outbyte [0] <<= 2;
118                 outbyte [0] |= (outbyte [1] >> 4) & 0x03;
119                 outbyte [1] <<= 4;
120                 outbyte [2] = DECODE_BYTE (linep [2]);
121                 outbyte [1] |= (outbyte [2] >> 2) & 0x0F;
122                 outbyte [2] <<= 6;
123                 outbyte [2] |= DECODE_BYTE (linep [3]) & 0x3F;
124             }
125             else
126             {
127                 outbyte [0] = DECODE_BYTE (linep [0]);
128                 if(lastlen > 1)
129                 {
130                     outbyte [1] = DECODE_BYTE (linep [1]);
131                     outbyte [0] <<= 2;
132                     outbyte [0] |= (outbyte [1] >> 4) & 0x03;
133                     outbyte [1] <<= 4;
134                 }
135                 if(lastlen > 2)
136                 {
137                     outbyte [2] = DECODE_BYTE (linep [2]);
138                     outbyte [1] |= (outbyte [2] >> 2) & 0x0F;
139                     outbyte [2] <<= 6;
140                 }
141                 /* outbyte [2] |= DECODE_BYTE (linep [3]) & 0x3F; */
142             }
143             /* Write the decoded bytes to the output file */
144 
145             if (linecnt > 3)
146             {
147                 if (fwrite (outbyte, 1, 3, outfile) != 3)
148                 {
149                     fprintf (stderr, "uudecode: Error writing to output file\n");
150                     exit (1);
151                 }
152             }
153             else
154             {
155                 if (fwrite (outbyte, 1, linecnt, outfile) != (size_t)linecnt)
156                 {
157                     fprintf (stderr, "uudecode: Error writing to output file\n");
158                     exit (1);
159                 }
160                 linecnt = 3;
161             }
162 
163         }
164         nRet = 1;
165         do
166         {    endl++;   }
167         while(endl[0] == '\r');
168         linebuf = endl;
169         endl = strchr(linebuf, '\r');
170         if (endl) linelen = endl-linebuf; else linelen = strlen(linebuf);
171     } while (linelen > 1);
172 
173     return nRet;
174 }
175 
isReady(UUEFile * uuc)176 int  isReady(UUEFile* uuc)
177 {
178     int i;
179     if(!uuc) return 0; /* Check pointers before use */
180 
181     for(i = 0; i < uuc->m_nSections; i++)
182     {
183         if(uuc->UUEparts[i] == NULL)
184             return 0;
185     }
186     return (i == uuc->m_nSections) && uuc->m_fname ;
187 }
188 
MakeUUEFile(int nsec,char * name,char * ID)189 UUEFile* MakeUUEFile(int nsec, char *name, char* ID)
190 {
191     UUEFile* uuc = scalloc(1,sizeof(UUEFile));
192     uuc->m_nSections = nsec;
193     if(nsec>0){
194         uuc->UUEparts = (char**)scalloc( nsec, sizeof(char*) );
195         if(nDelMsg || nCutMsg)
196             uuc->toBeDeleted = (DelCutStruct*)scalloc(nsec,sizeof(DelCutStruct));
197     }
198     if(name)
199     uuc->m_fname = sstrdup(name);
200     uuc->ID = ID ? sstrdup(ID) : uuc->m_fname;
201     return uuc;
202 }
203 
204 
CompareUUEFile(char * p_e1,char * p_e2)205 int  CompareUUEFile(char *p_e1, char *p_e2)
206 {
207    UUEFile  *a, *b;
208    if(!p_e1 || !p_e2) return p_e1>p_e2? 1: p_e1==p_e2? 0:-1;
209 
210    a = (UUEFile*)p_e1;
211    b = (UUEFile*)p_e2;
212    return strcmp(a->ID,b->ID);
213 }
214 
FreeUUEFile(char * entry)215 int  FreeUUEFile(char *entry)
216 {
217     if(entry)
218     {
219         UUEFile  *uuc;
220         int i;
221         uuc = (UUEFile *)entry;
222         for(i = 0; i < uuc->m_nSections; i++)
223             nfree(uuc->UUEparts[i]);
224         nfree(uuc->toBeDeleted);
225         nfree(uuc->description);
226         if(uuc->m_fname != uuc->ID)
227             nfree(uuc->ID);
228         nfree(uuc->m_fname);
229     }
230     return 1;
231 }
232 
AddPart(UUEFile * uuc,char * msgBody,char * uuepart,int section,int slen)233 void AddPart(UUEFile* uuc, char* msgBody, char* uuepart, int section, int slen)
234 {
235     if(!uuc || !uuepart) return; /* Check pointers before use */
236 
237     if(section > uuc->m_nSections || uuc->m_nAdded == uuc->m_nSections ||
238        uuc->UUEparts[section-1])
239         return;
240 
241     if(section == 1)
242     {
243         uuc->description = sstrdup((char*)xmsg.subj);
244         uuc->origin.zone  = xmsg.orig.zone;
245         uuc->origin.net   = xmsg.orig.net;
246         uuc->origin.node  = xmsg.orig.node;
247         uuc->origin.point = xmsg.orig.point;
248         if(nDelMsg || nCutMsg) {
249             uuc->toBeDeleted[0].nBegCut = uuepart - msgBody;
250             uuc->toBeDeleted[0].nEndCut = slen;
251 			uuc->toBeDeleted[0].nDelMsg = currMsgUid;
252         }
253     }
254 
255     uuc->UUEparts[section-1] = scalloc( slen+1, sizeof(char) );
256     strncpy(uuc->UUEparts[section-1],uuepart,slen);
257     if(nDelMsg || nCutMsg)
258     {
259         uuc->toBeDeleted[uuc->m_nAdded].nDelMsg = currMsgUid;
260     }
261     uuc->m_nAdded++;
262     if((uuc->m_nAdded == uuc->m_nSections) && isReady(uuc))
263     {
264         MakeFile(uuc);
265     }
266 }
267 #if !defined(UNIX) && !defined(OS2) && !defined(__DJGPP__) && !defined (__EMX__)
268 #   include <windows.h>
269 #endif
270 
MakeFile(UUEFile * uuc)271 void MakeFile(UUEFile* uuc)
272 {
273     FILE *out;
274     char *fname = NULL;
275     int i, nodel=0;
276     s_textDupeEntry *msg;
277 
278     if(!uuc) return; /* Check pointers before use */
279 
280     msg = scalloc(sizeof(s_textDupeEntry),1);
281 
282     msg->filename = sstrdup(uuc->m_fname);
283     msg->areaname = sstrdup(currArea->areaName);
284     msg->from     = sstrdup((char*)xmsg.from);
285 
286     if(dupeDetection(msg) == 1)
287     {
288         for(i = 0; i < 9; i++)
289         {
290             if(patimat(uuc->m_fname,invalidExt[i]))
291                 xstrcat(&uuc->m_fname,"_");
292         }
293         xstrscat(&fname,config->protInbound,uuc->m_fname,NULL);
294         if(!fexist(fname)) {
295             out = fopen(fname, "wb");
296             if(out) {
297                 for(i = 0; i < uuc->m_nSections; i++)
298                 {
299                     if( DecodePart(uuc->UUEparts[i], out) == 0)
300                         break;
301                 }
302                 fclose(out);
303                 if(i == uuc->m_nSections)
304                 {
305                     w_log(LL_INFO, "file: %15s has %d complete sections is saved",
306                         uuc->m_fname,uuc->m_nSections);
307                     MakeTicFile(uuc);
308                     nodel = 0;
309                 }
310                 else
311                 {
312                     remove(fname);
313                     nodel = 1;
314                 }
315             } else {
316                 w_log(LL_ERROR,"file: %15s can not be created", uuc->m_fname);
317             }
318         } else {
319             w_log(LL_CREAT,"file: %15s detected in inbound", uuc->m_fname);
320         }
321     }
322     else
323     {
324         w_log(LL_FUNC,"%s::MakeFile(), dupe file %15s detected", __FILE__,uuc->m_fname);
325     }
326     if( (!nodel) && (nDelMsg || nCutMsg) )
327     {
328         for( i = 0; i < uuc->m_nSections; i++ )
329         {
330             if ( (nMaxDeleted > 0) && (toBeDeleted[nMaxDeleted-1].nDelMsg == uuc->toBeDeleted[i].nDelMsg))
331                 continue; /* do not delete multiUUE message twice */
332 
333             toBeDeleted[nMaxDeleted].nDelMsg = uuc->toBeDeleted[i].nDelMsg;
334             toBeDeleted[nMaxDeleted].nBegCut = uuc->toBeDeleted[i].nBegCut;
335             toBeDeleted[nMaxDeleted].nEndCut = uuc->toBeDeleted[i].nEndCut;
336             nMaxDeleted++;
337         }
338     }
339     tree_delete(&UUEFileTree, CompareUUEFile,(char*)uuc, FreeUUEFile);
340     nfree(fname);
341     w_log(LL_FUNC,"%s::MakeFile(), exit", __FILE__);
342 }
343 
MakeTicFile(UUEFile * uuc)344 void MakeTicFile(UUEFile* uuc)
345 {
346    unsigned int i=0;
347    struct stat stbuf;
348    FILE *tichandle  = NULL;
349    char *newticfile = NULL;
350    char *fname      = NULL;
351    char *areagroup  = NULL;
352    s_link* link;
353 
354    if(!uuc) return; /* Check pointers before use */
355 
356    link = getLinkFromAddr( config,*(currArea->useAka) );
357    while( !link && i < config->addrCount )
358    {
359       link = getLinkFromAddr( config, config->addr[i] );
360       i++;
361    }
362    if(!link)
363    {
364       w_log(LL_INFO, "tic file not created for file %s", uuc->m_fname);
365       return ;
366    }
367 
368    xstrscat(&fname,config->protInbound,uuc->m_fname,NULL);
369 
370    stat(fname,&stbuf);
371    if(stbuf.st_size == 0)
372    {
373        remove(fname);
374        return;
375    }
376 
377    newticfile=makeUniqueDosFileName(config->protInbound,"tic",config);
378 
379    tichandle=fopen(newticfile,"wb");
380 
381    areagroup = findFileGroup(currArea->areaName);
382 
383 
384    if (config->outtab != NULL)
385        recodeToTransportCharset((CHAR*)uuc->description);
386 
387    fprintf(tichandle, "Created by %s, written by Max Chernogor\r\n",versionStr);
388    fprintf(tichandle, "File %s\r\n", uuc->m_fname);
389    fprintf(tichandle, "Area %s\r\n", areagroup);
390    if(currArea->areaName)
391      fprintf(tichandle, "Areadesc UUE decoded from %s\r\n", currArea->areaName);
392    if(uuc->description)
393      fprintf(tichandle, "Desc %s\r\n", uuc->description);
394    fprintf(tichandle, "From %s\r\n", aka2str(link->hisAka));
395    fprintf(tichandle, "To %s\r\n",   aka2str(link->hisAka));
396    fprintf(tichandle, "Origin %s\r\n", aka2str(uuc->origin));
397    fprintf(tichandle, "Size %lu\r\n", (unsigned long)stbuf.st_size);
398    fprintf(tichandle, "Crc %08lX\r\n", (unsigned long) filecrc32(fname));
399    if(link->filefix.pwd)
400      fprintf(tichandle, "Pw %s\r\n", link->filefix.pwd);
401 
402    fclose(tichandle);
403    w_log(LL_CREAT, "tic file:%s created for file:%s",newticfile, uuc->m_fname);
404    nfree(newticfile);
405    nfree(areagroup);
406 }
407