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