ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/uulib/uucheck.c
Revision: 1.12
Committed: Thu Jan 4 11:34:50 2007 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +1 -6 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 /*
2     * This file is part of uudeview, the simple and friendly multi-part multi-
3 root 1.2 * file uudecoder program (c) 1994-2001 by Frank Pilhofer. The author may
4     * be contacted at fp@fpx.de
5 root 1.1 *
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     #ifdef HAVE_CONFIG_H
18     #include "config.h"
19     #endif
20    
21     #ifdef SYSTEM_WINDLL
22     #include <windows.h>
23     #endif
24     #ifdef SYSTEM_OS2
25     #include <os2.h>
26     #endif
27    
28     /*
29     * uucheck.c
30     *
31     * Various checking and processing of one input part
32     **/
33    
34     #include <stdio.h>
35     #include <ctype.h>
36    
37     #ifdef STDC_HEADERS
38     #include <stdlib.h>
39     #include <string.h>
40     #endif
41     #ifdef HAVE_MALLOC_H
42     #include <malloc.h>
43     #endif
44     #ifdef HAVE_UNISTD_H
45     #include <unistd.h>
46     #endif
47     #ifdef HAVE_MEMORY_H
48     #include <memory.h>
49     #endif
50    
51 root 1.2 #include <uudeview.h>
52 root 1.1 #include <uuint.h>
53     #include <fptools.h>
54     #include <uustring.h>
55    
56 root 1.8 char * uucheck_id = "$Id$";
57 root 1.1
58     /*
59     * Arbitrary number. This is the maximum number of part numbers we
60     * store for our have-parts and missing-parts lists
61     */
62    
63     #define MAXPLIST 256
64    
65    
66     /*
67     * forward declarations of local functions
68     */
69    
70     static char * UUGetFileName (char *, char *, char *);
71     static int UUGetPartNo (char *, char **, char **);
72    
73     /*
74     * State of Scanner function and PreProcessPart
75     */
76    
77     int lastvalid, lastenc, nofnum;
78     char *uucheck_lastname;
79     char *uucheck_tempname;
80     static int lastpart = 0;
81     static char *nofname = "UNKNOWN";
82    
83     /*
84     * special characters we allow an unquoted filename to have
85     */
86    
87     static char *fnchars = "._-~!";
88    
89     /*
90     * Policy for extracting a part number from the subject line.
91     * usually, look for part numbers in () brackets first, then in []
92     */
93    
94     static char *brackchr[] = {
95     "()[]", "[]()"
96     };
97    
98     /*
99     * Extract a filename from the subject line. We need anything to identify
100     * the name of the program for sorting. If a nice filename cannot be found,
101     * the subject line itself is used
102     * ptonum is, if not NULL, a pointer to the part number in the subject line,
103     * so that it won't be used as filename.
104     **/
105    
106     static char *
107     UUGetFileName (char *subject, char *ptonum, char *ptonend)
108     {
109     char *ptr = subject, *iter, *result, *part;
110     int count, length=0, alflag=0;
111    
112     /*
113     * If this file has no subject line, assume it is the next part of the
114     * previous file (this is done in UUPreProcessPart)
115     **/
116    
117     if (subject == NULL)
118     return NULL;
119    
120     /*
121     * If the subject starts with 'Re', it is ignored
122     * REPosts or RETries are not ignored!
123     **/
124    
125     if (uu_ignreply &&
126     (subject[0] == 'R' || subject[0] == 'r') &&
127     (subject[1] == 'E' || subject[1] == 'e') &&
128     (subject[2] == ':' || subject[2] == ' ')) {
129 root 1.6 return uu_FileNameCallback ? uu_FileNameCallback(uu_FNCBArg, subject, NULL) : NULL;
130 root 1.1 }
131    
132     /*
133     * Ignore a "Repost" prefix of the subject line. We don't want to get
134     * a file named "Repost" :-)
135     **/
136    
137 root 1.5 if (_FP_strnicmp (subject, "repost", 6) == 0)
138 root 1.1 subject += 6;
139 root 1.5 if (_FP_strnicmp (subject, "re:", 3) == 0)
140 root 1.1 subject += 3;
141    
142     while (*subject == ' ' || *subject == ':') subject++;
143    
144 root 1.5 part = _FP_stristr (subject, "part");
145 root 1.1 if (part == subject) {
146     subject += 4;
147     while (*subject == ' ') subject++;
148     }
149    
150     /*
151     * If the file was encoded by uuenview, then the filename is enclosed
152     * in [brackets]. But check what's inside these bracket's, try not to
153     * fall for something other than a filename
154     */
155    
156     ptr = subject;
157     while ((iter = strchr (ptr, '[')) != NULL) {
158     if (strchr (iter, ']') == NULL) {
159     ptr = iter + 1;
160     continue;
161     }
162     iter++;
163     while (isspace (*iter))
164     iter++;
165     count = length = alflag = 0;
166     while (iter[count] &&
167     (isalnum (iter[count]) || strchr (fnchars, iter[count])!=NULL)) {
168     if (isalpha (iter[count]))
169     alflag++;
170     count++;
171     }
172     if (count<4 || alflag==0) {
173     ptr = iter + 1;
174     continue;
175     }
176     length = count;
177     while (isspace (iter[count]))
178     count++;
179     if (iter[count] == ']') {
180     ptr = iter;
181     break;
182     }
183     length = 0;
184     ptr = iter + 1;
185     }
186    
187     /*
188     * new filename detection routine, fists mostly for files by ftp-by-email
189     * servers that create subject lines with ftp.host.address:/full/path/file
190     * on them. We look for slashes and take the filename from after the last
191     * one ... or at least we try to.
192     */
193    
194     if (length == 0) {
195     ptr = subject;
196     while ((iter = strchr (ptr, '/')) != NULL) {
197     if (iter >= ptonum && iter <= ptonend) {
198     ptr = iter + 1;
199     continue;
200     }
201     count = length = 0;
202     iter++;
203     while (iter[count] &&
204     (isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL))
205     count++;
206     if (iter[count] == ' ' && length > 4) {
207     length = count;
208     break;
209     }
210     ptr = iter + ((count)?count:1);
211     }
212     }
213    
214     /*
215     * Look for two alphanumeric strings separated by a '.'
216     * (That's most likely a filename)
217     **/
218    
219     if (length == 0) {
220     ptr = subject;
221 root 1.3 /* #warning another experimental change */
222     /*while (*ptr && *ptr != 0x0a && *ptr != 0x0d && ptr != part) {*/
223     while (*ptr && *ptr != 0x0a && *ptr != 0x0d) {
224 root 1.1 iter = ptr;
225     count = length = alflag = 0;
226    
227 root 1.5 if (_FP_strnicmp (ptr, "ftp", 3) == 0) {
228 root 1.1 /* hey, that's an ftp address */
229     while (isalpha (*ptr) || isdigit (*ptr) || *ptr == '.')
230     ptr++;
231     continue;
232     }
233    
234     while ((isalnum(*iter)||strchr(fnchars, *iter)!=NULL||
235     *iter=='/') && *iter && iter != ptonum && *iter != '.') {
236     if (isalpha (*iter))
237     alflag = 1;
238    
239     count++; iter++;
240     }
241     if (*iter == '\0' || iter == ptonum) {
242     if (iter == ptonum)
243     ptr = ptonend;
244     else
245     ptr = iter;
246    
247     length = 0;
248     continue;
249     }
250 root 1.3
251     /* #warning multi-part change experimental, make pluggable */
252     /* if (*iter++ != '.' || count > 32 || alflag == 0) { */
253     if (*iter++ != '.' || count > 32) {
254 root 1.1 ptr = iter;
255     length = 0;
256     continue;
257     }
258 root 1.3
259 root 1.9 /* a dot followed by sth. unesthetically doesn't look right */
260     if (*iter < '0') {
261 root 1.3 ptr = iter + 1;
262     length = 0;
263     continue;
264     }
265    
266 root 1.5 if (_FP_strnicmp (iter, "edu", 3) == 0 ||
267     _FP_strnicmp (iter, "gov", 3) == 0) {
268 root 1.1 /* hey, that's an ftp address */
269     while (isalpha (*iter) || isdigit (*iter) || *iter == '.')
270     iter++;
271     ptr = iter;
272     length = 0;
273     continue;
274     }
275    
276     length += count + 1;
277     count = 0;
278    
279     while ((isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL||
280     iter[count]=='/') && iter[count] && iter[count] != '.')
281     count++;
282    
283     if (iter[count]==':' && iter[count+1]=='/') {
284     /* looks like stuff from a mail server */
285     ptr = iter + 1;
286     length = 0;
287     continue;
288     }
289    
290     if (count > 8 || iter == ptonum) {
291     ptr = iter;
292     length = 0;
293     continue;
294     }
295    
296     if (iter[count] != '.') {
297     length += count;
298     break;
299     }
300    
301     while (iter[count] &&
302     (isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL||
303     iter[count]=='/'))
304     count++;
305    
306     if (iter[count]==':' && iter[count+1]=='/') {
307     /* looks like stuff from a mail server */
308     ptr = iter + 1;
309     length = 0;
310     continue;
311     }
312    
313     if (count < 12 && iter != ptonum) {
314     length += count;
315     break;
316     }
317    
318     ptr = iter;
319     length = 0;
320     }
321     }
322    
323     if (length == 0) { /* No filename found, use subject line for ident */
324     ptr = subject;
325    
326     while (*ptr && !isalpha (*ptr))
327     ptr++;
328    
329     while ((isalnum(ptr[length])||strchr(fnchars,ptr[length])!=NULL||
330     ptr[length] == '/') &&
331     ptr[length] && ptr+length!=part && ptr+length!=ptonum)
332     length++;
333    
334     if (length) {
335     if (ptr[length] == '\0' || ptr[length] == 0x0a || ptr[length] == 0x0d) {
336     length--;
337    
338     /*
339     * I used to cut off digits from the end of the string, but
340     * let's try to live without. We want to distinguish
341     * DUTCH951 from DUTCH952
342     *
343     * while ((ptr[length] == ' ' || isdigit (ptr[length])) && length > 0)
344     * length--;
345     */
346     }
347     else {
348     length--;
349    
350     while (ptr[length] == ' ' && length > 0)
351     length--;
352     }
353     length++;
354     }
355     }
356    
357     if (length == 0) { /* Still found nothing? We need *something*! */
358     ptr = nofname;
359     length = strlen (nofname);
360     }
361    
362     if ((result = (char *) malloc (length + 1)) == NULL) {
363     UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
364     uustring (S_OUT_OF_MEMORY), length+1);
365     return NULL;
366     }
367    
368     memcpy (result, ptr, length);
369     result[length] = '\0';
370    
371 root 1.6 return uu_FileNameCallback ? uu_FileNameCallback(uu_FNCBArg, subject, result) : result;
372 root 1.1 }
373    
374     /*
375     * Extract the Part Number from the subject line.
376     * We look first for numbers in (#/#)'s, then for numbers in [#/#]'s
377     * and then for digits that are not part of a string.
378     * If we cannot find anything, assume it is the next part of the
379     * previous file.
380     * If we find a part number, we put a pointer to it in *where. This is
381     * done so that the UUGetFileName function doesn't accidentally use the
382     * part number as the file name. *whend points to the end of this part
383     * number.
384     **/
385    
386     static int
387     UUGetPartNo (char *subject, char **where, char **whend)
388     {
389     char *ptr = subject, *iter, *delim, bdel[2]=" ";
390     int count, length=0, bpc;
391    
392     *where = NULL; bdel[0] = ' ';
393     *whend = NULL; bdel[1] = '\0';
394    
395     iter = NULL;
396     delim = "";
397    
398     if (subject == NULL)
399     return -1;
400    
401     if (uu_ignreply &&
402     (subject[0] == 'R' || subject[0] == 'r') && /* Ignore replies, but not */
403     (subject[1] == 'E' || subject[1] == 'e') && /* reposts */
404     (subject[2] == ':' || subject[2] == ' '))
405     return -2;
406    
407     /*
408     * First try numbers in () or [] (or vice versa, according to bracket
409     * policy)
410 root 1.7 * For multiple occurences, give priority to the bracket with a slash
411     * or the last one, whichever is "found" first.
412 root 1.1 */
413    
414     for (bpc=0, length=0; brackchr[uu_bracket_policy][bpc]; bpc+=2) {
415 root 1.7 iter = subject;
416     length = 0;
417     while ((iter = strchr (iter, brackchr[uu_bracket_policy][bpc])) != NULL) {
418     int plength;
419    
420     count = 0; iter++;
421 root 1.1
422     while (*iter == ' ' || *iter == '#')
423     iter++;
424    
425     if (!isdigit (*iter)) {
426     continue;
427     }
428     while (isdigit (iter[count]))
429     count++;
430    
431 root 1.7 if (iter[count] == '\0') {
432     iter += count;
433 root 1.1 break;
434     }
435 root 1.7
436     plength = count;
437    
438 root 1.1 if (iter[count] == brackchr[uu_bracket_policy][bpc+1]) {
439     *where = iter;
440     bdel[0] = brackchr[uu_bracket_policy][bpc+1];
441     delim = bdel;
442 root 1.7 length = plength;
443     continue;
444 root 1.1 }
445 root 1.7
446 root 1.1 while (iter[count] == ' ' || iter[count] == '#' ||
447     iter[count] == '/' || iter[count] == '\\') count++;
448    
449 root 1.5 if (_FP_strnicmp (iter + count, "of", 2) == 0)
450 root 1.1 count += 2;
451    
452     while (iter[count] == ' ') count++;
453     while (isdigit (iter[count])) count++;
454     while (iter[count] == ' ') count++;
455    
456     if (iter[count] == brackchr[uu_bracket_policy][bpc+1]) {
457     *where = iter;
458     bdel[0] = brackchr[uu_bracket_policy][bpc+1];
459     delim = bdel;
460 root 1.7 length = plength;
461 root 1.1 break;
462     }
463     }
464     if (length)
465 root 1.7 {
466     iter = *where; /* strange control flow, but less changes == less hassle */
467     break;
468     }
469 root 1.1 }
470    
471     /*
472     * look for the string "part " followed by a number
473     */
474    
475     if (length == 0) {
476 root 1.5 if ((iter = _FP_stristr (subject, "part ")) != NULL) {
477 root 1.1 iter += 5;
478    
479     while (isspace (*iter) || *iter == '.' || *iter == '-')
480     iter++;
481    
482     while (isdigit (iter[length]))
483     length++;
484    
485     if (length == 0) {
486 root 1.5 if (_FP_strnicmp (iter, "one", 3) == 0) length = 1;
487     else if (_FP_strnicmp (iter, "two", 3) == 0) length = 2;
488     else if (_FP_strnicmp (iter, "three", 5) == 0) length = 3;
489     else if (_FP_strnicmp (iter, "four", 4) == 0) length = 4;
490     else if (_FP_strnicmp (iter, "five", 4) == 0) length = 5;
491     else if (_FP_strnicmp (iter, "six", 3) == 0) length = 6;
492     else if (_FP_strnicmp (iter, "seven", 5) == 0) length = 7;
493     else if (_FP_strnicmp (iter, "eight", 5) == 0) length = 8;
494     else if (_FP_strnicmp (iter, "nine", 4) == 0) length = 9;
495     else if (_FP_strnicmp (iter, "ten", 3) == 0) length = 10;
496 root 1.1
497     if (length && (*whend = strchr (iter, ' '))) {
498     *where = iter;
499     return length;
500     }
501     else
502     length = 0;
503     }
504     else {
505     *where = iter;
506     delim = "of";
507     }
508     }
509     }
510    
511     /*
512     * look for the string "part" followed by a number
513     */
514    
515     if (length == 0) {
516 root 1.5 if ((iter = _FP_stristr (subject, "part")) != NULL) {
517 root 1.1 iter += 4;
518    
519     while (isspace (*iter) || *iter == '.' || *iter == '-')
520     iter++;
521    
522     while (isdigit (iter[length]))
523     length++;
524    
525     if (length == 0) {
526 root 1.5 if (_FP_strnicmp (iter, "one", 3) == 0) length = 1;
527     else if (_FP_strnicmp (iter, "two", 3) == 0) length = 2;
528     else if (_FP_strnicmp (iter, "three", 5) == 0) length = 3;
529     else if (_FP_strnicmp (iter, "four", 4) == 0) length = 4;
530     else if (_FP_strnicmp (iter, "five", 4) == 0) length = 5;
531     else if (_FP_strnicmp (iter, "six", 3) == 0) length = 6;
532     else if (_FP_strnicmp (iter, "seven", 5) == 0) length = 7;
533     else if (_FP_strnicmp (iter, "eight", 5) == 0) length = 8;
534     else if (_FP_strnicmp (iter, "nine", 4) == 0) length = 9;
535     else if (_FP_strnicmp (iter, "ten", 3) == 0) length = 10;
536 root 1.1
537     if (length && (*whend = strchr (iter, ' '))) {
538     *where = iter;
539     return length;
540     }
541     else
542     length = 0;
543     }
544     else {
545     *where = iter;
546     delim = "of";
547     }
548     }
549     }
550    
551     /*
552     * look for [0-9]* "of" [0-9]*
553     */
554    
555     if (length == 0) {
556 root 1.5 if ((iter = _FP_strirstr (subject, "of")) != NULL) {
557 root 1.1 while (iter>subject && isspace (*(iter-1)))
558     iter--;
559     if (isdigit(*(iter-1))) {
560     while (iter>subject && isdigit (*(iter-1)))
561     iter--;
562     if (!isdigit (*iter) && !isalpha (*iter) && *iter != '.')
563     iter++;
564     ptr = iter;
565    
566     while (isdigit (*ptr)) {
567     ptr++; length++;
568     }
569     *where = iter;
570     delim = "of";
571     }
572     }
573     }
574    
575     /*
576     * look for whitespace-separated (or '/'-separated) digits
577     */
578    
579     if (length == 0) {
580     ptr = subject;
581    
582     while (*ptr && length==0) {
583     while (*ptr && !isdigit (*ptr))
584     ptr++;
585     if (isdigit (*ptr) && (ptr==subject || *ptr==' ' || *ptr=='/')) {
586     while (isdigit (ptr[length]))
587     length++;
588     if (ptr[length]!='\0' && ptr[length]!=' ' && ptr[length]!='/') {
589     ptr += length;
590     length = 0;
591     }
592     else {
593     iter = ptr;
594     bdel[0] = ptr[length];
595     delim = bdel;
596     }
597     }
598     else {
599     while (isdigit (*ptr))
600     ptr++;
601     }
602     }
603     }
604    
605     /*
606     * look for _any_ digits -- currently disabled, because it also fell
607     * for "part numbers" in file names
608     */
609    
610     #if 0
611     if (length == 0) {
612     count = strlen(subject) - 1;
613     ptr = subject;
614    
615     while (count > 0) {
616     if (!isdigit(ptr[count])||isalpha(ptr[count+1])||ptr[count+1] == '.') {
617     count--;
618     continue;
619     }
620     length = 0;
621    
622     while (count >= 0 && isdigit (ptr[count])) {
623     count--; length++;
624     }
625     if (count>=0 && ((isalpha (ptr[count]) &&
626     (ptr[count] != 's' || ptr[count+1] != 't') &&
627     (ptr[count] != 'n' || ptr[count+1] != 'd')) ||
628     ptr[count] == '/' || ptr[count] == '.' ||
629     ptr[count] == '-' || ptr[count] == '_')) {
630     length = 0;
631     continue;
632     }
633     count++;
634     iter = ptr + count;
635    
636     if (length > 4) {
637     length = 0;
638     continue;
639     }
640     *where = iter;
641     delim = "of";
642     break;
643     }
644     }
645     #endif
646    
647     /*
648     * look for part numbering as string
649     */
650    
651     if (length == 0) {
652     /*
653     * some people use the strangest things, including spelling mistakes :-)
654     */
655 root 1.5 if ((iter = _FP_stristr (subject, "first")) != NULL) length = 1;
656     else if ((iter = _FP_stristr (subject, "second")) != NULL) length = 2;
657     else if ((iter = _FP_stristr (subject, "third")) != NULL) length = 3;
658     else if ((iter = _FP_stristr (subject, "forth")) != NULL) length = 4;
659     else if ((iter = _FP_stristr (subject, "fourth")) != NULL) length = 4;
660     else if ((iter = _FP_stristr (subject, "fifth")) != NULL) length = 5;
661     else if ((iter = _FP_stristr (subject, "sixth")) != NULL) length = 6;
662     else if ((iter = _FP_stristr (subject, "seventh")) != NULL) length = 7;
663     else if ((iter = _FP_stristr (subject, "eigth")) != NULL) length = 8;
664     else if ((iter = _FP_stristr (subject, "eighth")) != NULL) length = 8;
665     else if ((iter = _FP_stristr (subject, "nineth")) != NULL) length = 9;
666     else if ((iter = _FP_stristr (subject, "ninth")) != NULL) length = 9;
667     else if ((iter = _FP_stristr (subject, "tenth")) != NULL) length = 10;
668 root 1.1 else iter = NULL;
669    
670     if (length && iter && (*whend = strchr (iter, ' '))) {
671     *where = iter;
672     return length;
673     }
674     else
675     length = 0;
676     }
677    
678     if (iter == NULL || length == 0) /* should be equivalent */
679     return -1;
680    
681     *where = iter;
682    
683     if (delim && delim[0]) {
684 root 1.5 if ((*whend=_FP_stristr (iter, delim)) != NULL && (*whend - *where) < 12) {
685 root 1.1 ptr = (*whend += strlen (delim));
686    
687     while (*ptr == ' ')
688     ptr++;
689    
690     if (isdigit (*ptr)) {
691     *whend = ptr;
692     while (isdigit (**whend))
693     *whend += 1;
694     }
695     }
696     else {
697     *whend = iter + length;
698     }
699     }
700     else {
701     *whend = iter + length;
702     }
703    
704     return atoi (iter);
705     }
706    
707     /*
708     * Obtain and process some information about the data.
709     **/
710    
711     uufile *
712     UUPreProcessPart (fileread *data, int *ret)
713     {
714     char *where, *whend, temp[80], *ptr, *p2;
715     uufile *result;
716    
717     if ((result = (uufile *) malloc (sizeof (uufile))) == NULL) {
718     UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
719     uustring (S_OUT_OF_MEMORY), sizeof (uufile));
720     *ret = UURET_NOMEM;
721     return NULL;
722     }
723     memset (result, 0, sizeof (uufile));
724    
725     if (data->partno) {
726     where = whend = NULL;
727     result->partno = data->partno;
728     }
729     else if (uu_dumbness) {
730     result->partno = -1;
731     where = whend = NULL;
732     }
733     else if ((result->partno=UUGetPartNo(data->subject,&where,&whend)) == -2) {
734     *ret = UURET_NODATA;
735     UUkillfile (result);
736     return NULL;
737     }
738    
739     if (data->filename != NULL) {
740 root 1.5 if ((result->filename = _FP_strdup (data->filename)) == NULL) {
741 root 1.1 UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
742     uustring (S_OUT_OF_MEMORY),
743     strlen (data->filename)+1);
744     *ret = UURET_NOMEM;
745     UUkillfile (result);
746     return NULL;
747     }
748     }
749     else
750     result->filename = NULL;
751    
752     if (uu_dumbness <= 1)
753     result->subfname = UUGetFileName (data->subject, where, whend);
754     else
755     result->subfname = NULL;
756    
757 root 1.5 result->mimeid = _FP_strdup (data->mimeid);
758     result->mimetype = _FP_strdup (data->mimetype);
759 root 1.1
760     if (result->partno == -1 &&
761     (data->uudet == PT_ENCODED || data->uudet == QP_ENCODED))
762     result->partno = 1;
763    
764     if (data->flags & FL_SINGLE) {
765     /*
766     * Don't touch this part. But it should really have a filename
767     */
768     if (result->filename == NULL) {
769     sprintf (temp, "%s.%03d", nofname, ++nofnum);
770 root 1.5 result->filename = _FP_strdup (temp);
771 root 1.1 }
772     if (result->subfname == NULL)
773 root 1.5 result->subfname = _FP_strdup (result->filename);
774 root 1.1
775     if (result->filename == NULL ||
776     result->subfname == NULL) {
777     UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
778     uustring (S_OUT_OF_MEMORY),
779     (result->filename==NULL)?
780     (strlen(temp)+1):(strlen(result->filename)+1));
781     *ret = UURET_NOMEM;
782     UUkillfile(result);
783     return NULL;
784     }
785     if (result->partno == -1)
786     result->partno = 1;
787     }
788     else if (result->subfname == NULL && data->uudet &&
789     (data->begin || result->partno == 1 ||
790     (!uu_dumbness && result->partno == -1 &&
791     (data->subject != NULL || result->filename != NULL)))) {
792     /*
793     * If it's the first part of something and has some valid data, but
794     * no subject or anything, initialize lastvalid
795     */
796     /*
797     * in this case, it really _should_ have a filename somewhere
798     */
799 root 1.8 if (result->filename != NULL && *result->filename)
800 root 1.5 result->subfname = _FP_strdup (result->filename);
801 root 1.1 else { /* if not, escape to UNKNOWN. We need to fill subfname */
802     sprintf (temp, "%s.%03d", nofname, ++nofnum);
803 root 1.5 result->subfname = _FP_strdup (temp);
804 root 1.1 }
805     /*
806     * in case the strdup failed
807     */
808     if (result->subfname == NULL) {
809     UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
810     uustring (S_OUT_OF_MEMORY),
811     (result->filename)?
812     (strlen(result->filename)+1):(strlen(temp)+1));
813     *ret = UURET_NOMEM;
814     UUkillfile (result);
815     return NULL;
816     }
817     /*
818     * if it's also got an 'end', or is the last part in a MIME-Mail,
819     * then don't set lastvalid
820     */
821     if (!data->end && (!data->partno || data->partno != data->maxpno)) {
822     /*
823     * initialize lastvalid
824     */
825     lastvalid = 1;
826     lastenc = data->uudet;
827     lastpart = result->partno = 1;
828 root 1.5 _FP_strncpy (uucheck_lastname, result->subfname, 256);
829 root 1.1 }
830     else
831     result->partno = 1;
832     }
833     else if (result->subfname == NULL && data->uudet && data->mimeid) {
834     /*
835     * if it's got a file name, use it. Else use the mime-id for identifying
836     * this part, and hope there's no other files encoded in the same message
837     * under the same id.
838     */
839     if (result->filename)
840 root 1.5 result->subfname = _FP_strdup (result->filename);
841 root 1.1 else
842 root 1.5 result->subfname = _FP_strdup (result->mimeid);
843 root 1.1 }
844     else if (result->subfname == NULL && data->uudet) {
845     /*
846     * ff we have lastvalid, use it. Make an exception for
847     * Base64-encoded files.
848     */
849     if (data->uudet == B64ENCODED) {
850     /*
851     * Assume it's the first part. I wonder why it's got no part number?
852     */
853 root 1.8 if (result->filename != NULL && *result->filename)
854 root 1.5 result->subfname = _FP_strdup (result->filename);
855 root 1.1 else { /* if not, escape to UNKNOWN. We need to fill subfname */
856     sprintf (temp, "%s.%03d", nofname, ++nofnum);
857 root 1.5 result->subfname = _FP_strdup (temp);
858 root 1.1 }
859     if (result->subfname == NULL) {
860     UUMessage (uucheck_id, __LINE__, UUMSG_ERROR,
861     uustring (S_OUT_OF_MEMORY),
862     (result->filename)?
863     (strlen(result->filename)+1):(strlen(temp)+1));
864     *ret = UURET_NOMEM;
865     UUkillfile (result);
866     return NULL;
867     }
868     lastvalid = 0;
869     }
870 root 1.4 else if (lastvalid && data->uudet == lastenc && result->partno == -1) {
871 root 1.5 result->subfname = _FP_strdup (uucheck_lastname);
872 root 1.1 result->partno = ++lastpart;
873    
874     /*
875     * if it's the last part, invalidate lastvalid
876     */
877     if (data->end || (data->partno && data->partno == data->maxpno))
878     lastvalid = 0;
879 root 1.4 }
880     else if (data->partno != -1 && result->filename) {
881 root 1.5 result->subfname = _FP_strdup (result->filename);
882 root 1.1 }
883     else {
884     /*
885     * it's got no info, it's got no begin, and we don't know anything
886     * about this part. Let's forget all about it.
887     */
888     *ret = UURET_NODATA;
889     UUkillfile (result);
890     return NULL;
891     }
892     }
893     else if (result->subfname == NULL && result->partno == -1) {
894     /*
895     * This, too, is a part without any useful information that we
896     * should forget about.
897     */
898     *ret = UURET_NODATA;
899     UUkillfile (result);
900     return NULL;
901     }
902     else if (result->subfname == NULL) {
903     /*
904     * This is a part without useful subject name, a valid part number
905     * but no encoded data. It *could* be the zeroeth part of something,
906     * but we don't care here. Just forget it.
907     */
908     *ret = UURET_NODATA;
909     UUkillfile (result);
910     return NULL;
911     }
912    
913     /*
914     * now, handle some cases where we have a useful subject but no
915     * useful part number
916     */
917    
918     if (result->partno == -1 && data->begin) {
919     /*
920     * hmm, this is reason enough to initialize lastvalid, at least
921     * if we have no end
922     */
923     if (!data->end) {
924 root 1.5 _FP_strncpy (uucheck_lastname, result->subfname, 256);
925 root 1.1 result->partno = lastpart = 1;
926     lastenc = data->uudet;
927     lastvalid = 1;
928     }
929     else
930     result->partno = 1;
931     }
932     else if (result->partno == -1 && data->uudet) {
933 root 1.5 if (lastvalid && _FP_stricmp (uucheck_lastname, result->subfname) == 0) {
934 root 1.1 /*
935     * if the subject filename is the same as last time, use part no
936     * of lastvalid. If at end, invalidate lastvalid
937     */
938     result->partno = ++lastpart;
939    
940     if (data->end)
941     lastvalid = 0;
942     }
943     else {
944     /*
945     * data but no part no. It's something UUInsertPartToList() should
946     * handle
947     */
948     goto skipcheck;
949     }
950     }
951     else if (result->partno == -1) {
952     /*
953     * it's got no data, so why should we need this one anyway?
954     */
955     *ret = UURET_NODATA;
956     UUkillfile (result);
957     return NULL;
958     }
959    
960     /*
961     * at this point, the part should have a valid subfname and a valid
962     * part number. If it doesn't, then fail.
963     */
964     if (result->subfname == NULL || result->partno == -1) {
965     *ret = UURET_NODATA;
966     UUkillfile (result);
967     return NULL;
968     }
969    
970     skipcheck:
971    
972     if (result->filename) {
973 root 1.5 if (*(ptr = _FP_cutdir (result->filename))) {
974     p2 = _FP_strdup (ptr);
975     _FP_free (result->filename);
976 root 1.1 result->filename = p2;
977     }
978     }
979    
980     result->data = data;
981     result->NEXT = NULL;
982    
983     *ret = UURET_OK;
984    
985     return result;
986     }
987    
988     /*
989     * Insert one part of a file into the global list
990     **/
991    
992     int
993     UUInsertPartToList (uufile *data)
994     {
995     uulist *iter = UUGlobalFileList, *unew;
996     uufile *fiter, *last;
997    
998     /*
999     * Part belongs together, if
1000 root 1.8 * (1) The MIME-IDs match, or
1001     * (2) The file name received from the subject lines match, and
1002     * (a) Not both parts have a begin line
1003     * (b) Not both parts have an end line
1004     * (c) Both parts don't have different MIME-IDs
1005     * (d) Both parts don't encode different files
1006     * (e) The other part wants to stay alone (FL_SINGLE)
1007 root 1.1 */
1008    
1009     /*
1010     * check if this part wants to be left alone. If so, don't bother
1011     * to do all the checks
1012     */
1013    
1014     while (iter) {
1015     if (data->data->flags & FL_SINGLE) {
1016     /* this space intentionally left blank */
1017     }
1018 root 1.8 else if ((data->mimeid && iter->mimeid &&
1019     strcmp (data->mimeid, iter->mimeid) == 0) ||
1020     (_FP_stricmp (data->subfname, iter->subfname) == 0 &&
1021     !(iter->begin && data->data->begin) &&
1022     !(iter->end && data->data->end) &&
1023     !(data->mimeid && iter->mimeid &&
1024     strcmp (data->mimeid, iter->mimeid) != 0) &&
1025     !(data->filename && iter->filename &&
1026     strcmp (data->filename, iter->filename) != 0) &&
1027     !(iter->flags & FL_SINGLE))) {
1028 root 1.1
1029     /*
1030 root 1.8 * Don't insert a part that is already there.
1031     *
1032     * Also don't add a part beyond the "end" marker (unless we
1033     * have a mimeid, which screws up the marker).
1034 root 1.1 */
1035    
1036 root 1.8 for (fiter=iter->thisfile; fiter; fiter=fiter->NEXT) {
1037     if (data->partno == fiter->partno)
1038     goto goahead;
1039     if (!iter->mimeid) {
1040     if (data->partno > fiter->partno && fiter->data->end) {
1041     goto goahead;
1042     }
1043     }
1044     }
1045 root 1.1
1046     if (iter->filename == NULL && data->filename != NULL) {
1047 root 1.5 if ((iter->filename = _FP_strdup (data->filename)) == NULL)
1048 root 1.1 return UURET_NOMEM;
1049     }
1050    
1051     /*
1052     * special case when we might have tagged a part as Base64 when the
1053     * file was really XX
1054     */
1055    
1056     if (data->data->uudet == B64ENCODED &&
1057     iter->uudet == XX_ENCODED && iter->begin) {
1058     data->data->uudet = XX_ENCODED;
1059     }
1060     else if (data->data->uudet == XX_ENCODED && data->data->begin &&
1061     iter->uudet == B64ENCODED) {
1062     iter->uudet = XX_ENCODED;
1063    
1064     fiter = iter->thisfile;
1065     while (fiter) {
1066     fiter->data->uudet = XX_ENCODED;
1067     fiter = fiter->NEXT;
1068     }
1069     }
1070    
1071     /*
1072     * If this is from a Message/Partial, we believe only the
1073     * iter->uudet from the first part
1074     */
1075     if (data->data->flags & FL_PARTIAL) {
1076     if (data->partno == 1) {
1077     iter->uudet = data->data->uudet;
1078     iter->flags = data->data->flags;
1079     }
1080     }
1081     else {
1082     if (data->data->uudet) iter->uudet = data->data->uudet;
1083     if (data->data->flags) iter->flags = data->data->flags;
1084     }
1085    
1086     if (iter->mode == 0 && data->data->mode != 0)
1087     iter->mode = data->data->mode;
1088     if (data->data->begin) iter->begin = (data->partno)?data->partno:1;
1089     if (data->data->end) iter->end = (data->partno)?data->partno:1;
1090    
1091     if (data->mimetype) {
1092 root 1.5 _FP_free (iter->mimetype);
1093     iter->mimetype = _FP_strdup (data->mimetype);
1094 root 1.1 }
1095    
1096     /*
1097     * insert part at the beginning
1098     */
1099    
1100     if (data->partno != -1 && data->partno < iter->thisfile->partno) {
1101     iter->state = UUFILE_READ;
1102     data->NEXT = iter->thisfile;
1103     iter->thisfile = data;
1104     return UURET_OK;
1105     }
1106    
1107     /*
1108     * insert part somewhere else
1109     */
1110    
1111     iter->state = UUFILE_READ; /* prepare for re-checking */
1112     fiter = iter->thisfile;
1113     last = NULL;
1114    
1115     while (fiter) {
1116     /*
1117     * if we find the same part no again, check which one looks better
1118     */
1119     if (data->partno == fiter->partno) {
1120     if (fiter->data->subject == NULL)
1121     return UURET_NODATA;
1122 root 1.5 else if (_FP_stristr (fiter->data->subject, "repost") != NULL &&
1123     _FP_stristr (data->data->subject, "repost") == NULL)
1124 root 1.1 return UURET_NODATA;
1125     else if (fiter->data->uudet && !data->data->uudet)
1126     return UURET_NODATA;
1127     else {
1128     /*
1129     * replace
1130     */
1131     data->NEXT = fiter->NEXT;
1132     fiter->NEXT = NULL;
1133     UUkillfile (fiter);
1134    
1135     if (last == NULL)
1136     iter->thisfile = data;
1137     else
1138     last->NEXT = data;
1139    
1140     return UURET_OK;
1141     }
1142     }
1143    
1144     /*
1145     * if at the end of the part list, add it
1146     */
1147    
1148     if (fiter->NEXT == NULL ||
1149     (data->partno != -1 && data->partno < fiter->NEXT->partno)) {
1150     data->NEXT = fiter->NEXT;
1151     fiter->NEXT = data;
1152    
1153     if (data->partno == -1)
1154     data->partno = fiter->partno + 1;
1155    
1156     return UURET_OK;
1157     }
1158     last = fiter;
1159     fiter = fiter->NEXT;
1160     }
1161    
1162     return UURET_OK; /* Shouldn't get here */
1163     }
1164     goahead:
1165     /*
1166     * we need iter below
1167     */
1168     if (iter->NEXT == NULL)
1169     break;
1170    
1171     iter = iter->NEXT;
1172     }
1173     /*
1174     * handle new entry
1175     */
1176    
1177     if (data->partno == -1) {
1178     /*
1179     * if it's got no part no, and it's MIME mail, then assume this is
1180     * part no. 1. If it's not MIME, then we can't handle it; if it
1181     * had a 'begin', it'd have got a part number assigned by
1182     * UUPreProcessPart().
1183     */
1184     if (data->data->uudet == B64ENCODED || data->data->uudet == BH_ENCODED)
1185     data->partno = 1;
1186     else
1187     return UURET_NODATA;
1188     }
1189    
1190 root 1.12 if ((unew = (uulist *) calloc (1, sizeof (uulist))) == NULL) {
1191 root 1.1 return UURET_NOMEM;
1192     }
1193    
1194 root 1.5 if ((unew->subfname = _FP_strdup (data->subfname)) == NULL) {
1195     _FP_free (unew);
1196 root 1.1 return UURET_NOMEM;
1197     }
1198    
1199     if (data->filename != NULL) {
1200 root 1.5 if ((unew->filename = _FP_strdup (data->filename)) == NULL) {
1201     _FP_free (unew->subfname);
1202     _FP_free (unew);
1203 root 1.1 return UURET_NOMEM;
1204     }
1205     }
1206     else
1207     unew->filename = NULL;
1208    
1209     if (data->mimeid != NULL) {
1210 root 1.5 if ((unew->mimeid = _FP_strdup (data->mimeid)) == NULL) {
1211     _FP_free (unew->subfname);
1212     _FP_free (unew->filename);
1213     _FP_free (unew);
1214 root 1.1 return UURET_NOMEM;
1215     }
1216     }
1217     else
1218     unew->mimeid = NULL;
1219    
1220     if (data->mimetype != NULL) {
1221 root 1.5 if ((unew->mimetype = _FP_strdup (data->mimetype)) == NULL) {
1222     _FP_free (unew->mimeid);
1223     _FP_free (unew->subfname);
1224     _FP_free (unew->filename);
1225     _FP_free (unew);
1226 root 1.1 return UURET_NOMEM;
1227     }
1228     }
1229     else
1230     unew->mimetype = NULL;
1231    
1232     unew->state = UUFILE_READ;
1233     unew->thisfile = data;
1234     unew->mode = data->data->mode;
1235     unew->uudet = data->data->uudet;
1236     unew->flags = data->data->flags;
1237 root 1.10 unew->begin = data->data->begin ? (data->partno ? data->partno : 1) : 0;
1238     unew->end = data->data->end ? (data->partno ? data->partno : 1) : 0;
1239 root 1.1
1240     if (iter == NULL)
1241     UUGlobalFileList = unew;
1242     else
1243     iter->NEXT = unew;
1244    
1245     return UURET_OK;
1246     }
1247    
1248     /*
1249     * At this point, all files are read in and stored in the
1250     * "UUGlobalFileList". Do some checking. All parts there?
1251     **/
1252    
1253     uulist *
1254     UUCheckGlobalList (void)
1255     {
1256     int misparts[MAXPLIST], haveparts[MAXPLIST];
1257     int miscount, havecount, count, flag, part;
1258     uulist *liter=UUGlobalFileList, *prev;
1259     uufile *fiter;
1260     long thesize;
1261    
1262     while (liter) {
1263     miscount = 0;
1264     thesize = 0;
1265    
1266     if (liter->state & UUFILE_OK) {
1267     liter = liter->NEXT;
1268     continue;
1269     }
1270     else if ((liter->uudet == QP_ENCODED ||
1271     liter->uudet == PT_ENCODED) &&
1272     (liter->flags & FL_SINGLE)) {
1273     if ((liter->flags&FL_PROPER)==0)
1274     liter->size = -1;
1275     else
1276     liter->size = liter->thisfile->data->length;
1277    
1278     liter->state = UUFILE_OK;
1279     continue;
1280     }
1281     else if ((fiter = liter->thisfile) == NULL) {
1282     liter->state = UUFILE_NODATA;
1283     liter = liter->NEXT;
1284     continue;
1285     }
1286    
1287     /*
1288     * Re-Check this file
1289     */
1290    
1291     flag = 0;
1292     miscount = 0;
1293     havecount = 0;
1294     thesize = 0;
1295     liter->state = UUFILE_READ;
1296    
1297     /*
1298     * search encoded data
1299     */
1300    
1301     while (fiter && !fiter->data->uudet) {
1302     if (havecount<MAXPLIST) {
1303     haveparts[havecount++] = fiter->partno;
1304     }
1305     fiter = fiter->NEXT;
1306     }
1307    
1308     if (fiter == NULL) {
1309     liter->state = UUFILE_NODATA;
1310     liter = liter->NEXT;
1311     continue;
1312     }
1313    
1314     if (havecount<MAXPLIST) {
1315     haveparts[havecount++] = fiter->partno;
1316     }
1317    
1318     if ((part = fiter->partno) > 1) {
1319     if (!fiter->data->begin) {
1320     for (count=1; count < part && miscount < MAXPLIST; count++)
1321     misparts[miscount++] = count;
1322     }
1323     }
1324    
1325     /*
1326     * don't care if so many parts are missing
1327     */
1328    
1329     if (miscount >= MAXPLIST) {
1330     liter->state = UUFILE_MISPART;
1331     liter = liter->NEXT;
1332     continue;
1333     }
1334    
1335     if (liter->uudet == B64ENCODED ||
1336     liter->uudet == QP_ENCODED ||
1337     liter->uudet == PT_ENCODED)
1338     flag |= 3; /* Don't need begin or end with Base64 or plain text*/
1339    
1340     if (fiter->data->begin) flag |= 1;
1341     if (fiter->data->end) flag |= 2;
1342     if (fiter->data->uudet) flag |= 4;
1343    
1344     /*
1345     * guess size of part
1346     */
1347    
1348     switch (fiter->data->uudet) {
1349     case UU_ENCODED:
1350     case XX_ENCODED:
1351     thesize += 3*fiter->data->length/4;
1352     thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */
1353     break;
1354     case B64ENCODED:
1355     thesize += 3*fiter->data->length/4;
1356     thesize -= fiter->data->length/52; /* substract 2 of 78 chars */
1357     break;
1358     case QP_ENCODED:
1359     case PT_ENCODED:
1360     thesize += fiter->data->length;
1361     break;
1362     }
1363    
1364     fiter = fiter->NEXT;
1365    
1366     while (fiter != NULL) {
1367     for (count=part+1; count<fiter->partno && miscount<MAXPLIST; count++)
1368     misparts[miscount++] = count;
1369    
1370     part = fiter->partno;
1371    
1372     if (havecount<MAXPLIST)
1373     haveparts[havecount++]=part;
1374    
1375     if (fiter->data->begin) flag |= 1;
1376     if (fiter->data->end) flag |= 2;
1377     if (fiter->data->uudet) flag |= 4;
1378    
1379     switch (fiter->data->uudet) {
1380     case UU_ENCODED:
1381     case XX_ENCODED:
1382     thesize += 3*fiter->data->length/4;
1383     thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */
1384     break;
1385     case B64ENCODED:
1386     thesize += 3*fiter->data->length/4;
1387     thesize -= fiter->data->length/52; /* substract 2 of 78 chars */
1388     break;
1389     case QP_ENCODED:
1390     case PT_ENCODED:
1391     thesize += fiter->data->length;
1392     break;
1393     }
1394    
1395     if (fiter->data->end)
1396     break;
1397    
1398     fiter = fiter->NEXT;
1399     }
1400    
1401     /*
1402     * if in fast mode, we don't notice an 'end'. So if its uu or xx
1403     * encoded, there's a begin line and encoded data, assume it's
1404     * there.
1405     */
1406    
1407     if (uu_fast_scanning && (flag & 0x01) && (flag & 0x04) &&
1408     (liter->uudet == UU_ENCODED || liter->uudet == XX_ENCODED))
1409     flag |= 2;
1410    
1411     /*
1412     * Set the parts we have and/or missing
1413     */
1414    
1415 root 1.5 _FP_free (liter->haveparts);
1416     _FP_free (liter->misparts);
1417 root 1.1
1418     liter->haveparts = NULL;
1419     liter->misparts = NULL;
1420    
1421     if (havecount) {
1422     if ((liter->haveparts=(int*)malloc((havecount+1)*sizeof(int)))!=NULL) {
1423     memcpy (liter->haveparts, haveparts, havecount*sizeof(int));
1424     liter->haveparts[havecount] = 0;
1425     }
1426     }
1427    
1428     if (miscount) {
1429     if ((liter->misparts=(int*)malloc((miscount+1)*sizeof(int)))!=NULL) {
1430     memcpy (liter->misparts, misparts, miscount*sizeof(int));
1431     liter->misparts[miscount] = 0;
1432     }
1433     liter->state |= UUFILE_MISPART;
1434     }
1435    
1436     /*
1437     * Finalize checking
1438     */
1439    
1440     if ((flag & 4) == 0) liter->state |= UUFILE_NODATA;
1441     if ((flag & 1) == 0) liter->state |= UUFILE_NOBEGIN;
1442     if ((flag & 2) == 0) liter->state |= UUFILE_NOEND;
1443    
1444     if ((flag & 7) == 7 && miscount==0) {
1445     liter->state = UUFILE_OK;
1446     }
1447    
1448     if ((uu_fast_scanning && (liter->flags&FL_PROPER)==0) || thesize<=0)
1449     liter->size = -1;
1450     else
1451     liter->size = thesize;
1452    
1453     if (liter->state==UUFILE_OK &&
1454     (liter->filename==NULL || liter->filename[0]=='\0')) {
1455     /*
1456     * Emergency backup if the file does not have a filename
1457     */
1458 root 1.5 _FP_free (liter->filename);
1459 root 1.1 if (liter->subfname && liter->subfname[0] &&
1460 root 1.5 _FP_strpbrk (liter->subfname, "()[];: ") == NULL)
1461     liter->filename = _FP_strdup (liter->subfname);
1462 root 1.1 else {
1463     sprintf (uucheck_tempname, "%s.%03d", nofname, ++nofnum);
1464 root 1.5 liter->filename = _FP_strdup (uucheck_tempname);
1465 root 1.1 }
1466     }
1467     liter = liter->NEXT;
1468     }
1469    
1470     /*
1471     * Sets back (PREV) links
1472     */
1473    
1474     liter = UUGlobalFileList;
1475     prev = NULL;
1476    
1477     while (liter) {
1478     liter->PREV = prev;
1479     prev = liter;
1480     liter = liter->NEXT;
1481     }
1482    
1483     return UUGlobalFileList;
1484     }
1485