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

File Contents

# Content
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 #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 #include <uudeview.h>
52 #include <uuint.h>
53 #include <fptools.h>
54 #include <uustring.h>
55
56 char * uucheck_id = "$Id$";
57
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 return uu_FileNameCallback ? uu_FileNameCallback(uu_FNCBArg, subject, NULL) : NULL;
130 }
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 if (_FP_strnicmp (subject, "repost", 6) == 0)
138 subject += 6;
139 if (_FP_strnicmp (subject, "re:", 3) == 0)
140 subject += 3;
141
142 while (*subject == ' ' || *subject == ':') subject++;
143
144 part = _FP_stristr (subject, "part");
145 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 /* #warning another experimental change */
222 /*while (*ptr && *ptr != 0x0a && *ptr != 0x0d && ptr != part) {*/
223 while (*ptr && *ptr != 0x0a && *ptr != 0x0d) {
224 iter = ptr;
225 count = length = alflag = 0;
226
227 if (_FP_strnicmp (ptr, "ftp", 3) == 0) {
228 /* 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
251 /* #warning multi-part change experimental, make pluggable */
252 /* if (*iter++ != '.' || count > 32 || alflag == 0) { */
253 if (*iter++ != '.' || count > 32) {
254 ptr = iter;
255 length = 0;
256 continue;
257 }
258
259 /* a dot followed by sth. unesthetically doesn't look right */
260 if (*iter < '0') {
261 ptr = iter + 1;
262 length = 0;
263 continue;
264 }
265
266 if (_FP_strnicmp (iter, "edu", 3) == 0 ||
267 _FP_strnicmp (iter, "gov", 3) == 0) {
268 /* 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 return uu_FileNameCallback ? uu_FileNameCallback(uu_FNCBArg, subject, result) : result;
372 }
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 * For multiple occurences, give priority to the bracket with a slash
411 * or the last one, whichever is "found" first.
412 */
413
414 for (bpc=0, length=0; brackchr[uu_bracket_policy][bpc]; bpc+=2) {
415 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
422 while (*iter == ' ' || *iter == '#')
423 iter++;
424
425 if (!isdigit (*iter)) {
426 continue;
427 }
428 while (isdigit (iter[count]))
429 count++;
430
431 if (iter[count] == '\0') {
432 iter += count;
433 break;
434 }
435
436 plength = count;
437
438 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 length = plength;
443 continue;
444 }
445
446 while (iter[count] == ' ' || iter[count] == '#' ||
447 iter[count] == '/' || iter[count] == '\\') count++;
448
449 if (_FP_strnicmp (iter + count, "of", 2) == 0)
450 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 length = plength;
461 break;
462 }
463 }
464 if (length)
465 {
466 iter = *where; /* strange control flow, but less changes == less hassle */
467 break;
468 }
469 }
470
471 /*
472 * look for the string "part " followed by a number
473 */
474
475 if (length == 0) {
476 if ((iter = _FP_stristr (subject, "part ")) != NULL) {
477 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 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
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 if ((iter = _FP_stristr (subject, "part")) != NULL) {
517 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 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
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 if ((iter = _FP_strirstr (subject, "of")) != NULL) {
557 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 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 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 if ((*whend=_FP_stristr (iter, delim)) != NULL && (*whend - *where) < 12) {
685 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 if ((result->filename = _FP_strdup (data->filename)) == NULL) {
741 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 result->mimeid = _FP_strdup (data->mimeid);
758 result->mimetype = _FP_strdup (data->mimetype);
759
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 result->filename = _FP_strdup (temp);
771 }
772 if (result->subfname == NULL)
773 result->subfname = _FP_strdup (result->filename);
774
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 if (result->filename != NULL && *result->filename)
800 result->subfname = _FP_strdup (result->filename);
801 else { /* if not, escape to UNKNOWN. We need to fill subfname */
802 sprintf (temp, "%s.%03d", nofname, ++nofnum);
803 result->subfname = _FP_strdup (temp);
804 }
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 _FP_strncpy (uucheck_lastname, result->subfname, 256);
829 }
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 result->subfname = _FP_strdup (result->filename);
841 else
842 result->subfname = _FP_strdup (result->mimeid);
843 }
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 if (result->filename != NULL && *result->filename)
854 result->subfname = _FP_strdup (result->filename);
855 else { /* if not, escape to UNKNOWN. We need to fill subfname */
856 sprintf (temp, "%s.%03d", nofname, ++nofnum);
857 result->subfname = _FP_strdup (temp);
858 }
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 else if (lastvalid && data->uudet == lastenc && result->partno == -1) {
871 result->subfname = _FP_strdup (uucheck_lastname);
872 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 }
880 else if (data->partno != -1 && result->filename) {
881 result->subfname = _FP_strdup (result->filename);
882 }
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 _FP_strncpy (uucheck_lastname, result->subfname, 256);
925 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 if (lastvalid && _FP_stricmp (uucheck_lastname, result->subfname) == 0) {
934 /*
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 if (*(ptr = _FP_cutdir (result->filename))) {
974 p2 = _FP_strdup (ptr);
975 _FP_free (result->filename);
976 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 * (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 */
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 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
1029 /*
1030 * 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 */
1035
1036 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
1046 if (iter->filename == NULL && data->filename != NULL) {
1047 if ((iter->filename = _FP_strdup (data->filename)) == NULL)
1048 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 _FP_free (iter->mimetype);
1093 iter->mimetype = _FP_strdup (data->mimetype);
1094 }
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 else if (_FP_stristr (fiter->data->subject, "repost") != NULL &&
1123 _FP_stristr (data->data->subject, "repost") == NULL)
1124 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 if ((unew = (uulist *) malloc (sizeof (uulist))) == NULL) {
1191 return UURET_NOMEM;
1192 }
1193
1194 {
1195 static uulist uulist_new;
1196 *unew = uulist_new; /* zero-initialise the structure */
1197 }
1198
1199 if ((unew->subfname = _FP_strdup (data->subfname)) == NULL) {
1200 _FP_free (unew);
1201 return UURET_NOMEM;
1202 }
1203
1204 if (data->filename != NULL) {
1205 if ((unew->filename = _FP_strdup (data->filename)) == NULL) {
1206 _FP_free (unew->subfname);
1207 _FP_free (unew);
1208 return UURET_NOMEM;
1209 }
1210 }
1211 else
1212 unew->filename = NULL;
1213
1214 if (data->mimeid != NULL) {
1215 if ((unew->mimeid = _FP_strdup (data->mimeid)) == NULL) {
1216 _FP_free (unew->subfname);
1217 _FP_free (unew->filename);
1218 _FP_free (unew);
1219 return UURET_NOMEM;
1220 }
1221 }
1222 else
1223 unew->mimeid = NULL;
1224
1225 if (data->mimetype != NULL) {
1226 if ((unew->mimetype = _FP_strdup (data->mimetype)) == NULL) {
1227 _FP_free (unew->mimeid);
1228 _FP_free (unew->subfname);
1229 _FP_free (unew->filename);
1230 _FP_free (unew);
1231 return UURET_NOMEM;
1232 }
1233 }
1234 else
1235 unew->mimetype = NULL;
1236
1237 unew->state = UUFILE_READ;
1238 unew->thisfile = data;
1239 unew->mode = data->data->mode;
1240 unew->uudet = data->data->uudet;
1241 unew->flags = data->data->flags;
1242 unew->begin = data->data->begin ? (data->partno ? data->partno : 1) : 0;
1243 unew->end = data->data->end ? (data->partno ? data->partno : 1) : 0;
1244
1245 if (iter == NULL)
1246 UUGlobalFileList = unew;
1247 else
1248 iter->NEXT = unew;
1249
1250 return UURET_OK;
1251 }
1252
1253 /*
1254 * At this point, all files are read in and stored in the
1255 * "UUGlobalFileList". Do some checking. All parts there?
1256 **/
1257
1258 uulist *
1259 UUCheckGlobalList (void)
1260 {
1261 int misparts[MAXPLIST], haveparts[MAXPLIST];
1262 int miscount, havecount, count, flag, part;
1263 uulist *liter=UUGlobalFileList, *prev;
1264 uufile *fiter;
1265 long thesize;
1266
1267 while (liter) {
1268 miscount = 0;
1269 thesize = 0;
1270
1271 if (liter->state & UUFILE_OK) {
1272 liter = liter->NEXT;
1273 continue;
1274 }
1275 else if ((liter->uudet == QP_ENCODED ||
1276 liter->uudet == PT_ENCODED) &&
1277 (liter->flags & FL_SINGLE)) {
1278 if ((liter->flags&FL_PROPER)==0)
1279 liter->size = -1;
1280 else
1281 liter->size = liter->thisfile->data->length;
1282
1283 liter->state = UUFILE_OK;
1284 continue;
1285 }
1286 else if ((fiter = liter->thisfile) == NULL) {
1287 liter->state = UUFILE_NODATA;
1288 liter = liter->NEXT;
1289 continue;
1290 }
1291
1292 /*
1293 * Re-Check this file
1294 */
1295
1296 flag = 0;
1297 miscount = 0;
1298 havecount = 0;
1299 thesize = 0;
1300 liter->state = UUFILE_READ;
1301
1302 /*
1303 * search encoded data
1304 */
1305
1306 while (fiter && !fiter->data->uudet) {
1307 if (havecount<MAXPLIST) {
1308 haveparts[havecount++] = fiter->partno;
1309 }
1310 fiter = fiter->NEXT;
1311 }
1312
1313 if (fiter == NULL) {
1314 liter->state = UUFILE_NODATA;
1315 liter = liter->NEXT;
1316 continue;
1317 }
1318
1319 if (havecount<MAXPLIST) {
1320 haveparts[havecount++] = fiter->partno;
1321 }
1322
1323 if ((part = fiter->partno) > 1) {
1324 if (!fiter->data->begin) {
1325 for (count=1; count < part && miscount < MAXPLIST; count++)
1326 misparts[miscount++] = count;
1327 }
1328 }
1329
1330 /*
1331 * don't care if so many parts are missing
1332 */
1333
1334 if (miscount >= MAXPLIST) {
1335 liter->state = UUFILE_MISPART;
1336 liter = liter->NEXT;
1337 continue;
1338 }
1339
1340 if (liter->uudet == B64ENCODED ||
1341 liter->uudet == QP_ENCODED ||
1342 liter->uudet == PT_ENCODED)
1343 flag |= 3; /* Don't need begin or end with Base64 or plain text*/
1344
1345 if (fiter->data->begin) flag |= 1;
1346 if (fiter->data->end) flag |= 2;
1347 if (fiter->data->uudet) flag |= 4;
1348
1349 /*
1350 * guess size of part
1351 */
1352
1353 switch (fiter->data->uudet) {
1354 case UU_ENCODED:
1355 case XX_ENCODED:
1356 thesize += 3*fiter->data->length/4;
1357 thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */
1358 break;
1359 case B64ENCODED:
1360 thesize += 3*fiter->data->length/4;
1361 thesize -= fiter->data->length/52; /* substract 2 of 78 chars */
1362 break;
1363 case QP_ENCODED:
1364 case PT_ENCODED:
1365 thesize += fiter->data->length;
1366 break;
1367 }
1368
1369 fiter = fiter->NEXT;
1370
1371 while (fiter != NULL) {
1372 for (count=part+1; count<fiter->partno && miscount<MAXPLIST; count++)
1373 misparts[miscount++] = count;
1374
1375 part = fiter->partno;
1376
1377 if (havecount<MAXPLIST)
1378 haveparts[havecount++]=part;
1379
1380 if (fiter->data->begin) flag |= 1;
1381 if (fiter->data->end) flag |= 2;
1382 if (fiter->data->uudet) flag |= 4;
1383
1384 switch (fiter->data->uudet) {
1385 case UU_ENCODED:
1386 case XX_ENCODED:
1387 thesize += 3*fiter->data->length/4;
1388 thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */
1389 break;
1390 case B64ENCODED:
1391 thesize += 3*fiter->data->length/4;
1392 thesize -= fiter->data->length/52; /* substract 2 of 78 chars */
1393 break;
1394 case QP_ENCODED:
1395 case PT_ENCODED:
1396 thesize += fiter->data->length;
1397 break;
1398 }
1399
1400 if (fiter->data->end)
1401 break;
1402
1403 fiter = fiter->NEXT;
1404 }
1405
1406 /*
1407 * if in fast mode, we don't notice an 'end'. So if its uu or xx
1408 * encoded, there's a begin line and encoded data, assume it's
1409 * there.
1410 */
1411
1412 if (uu_fast_scanning && (flag & 0x01) && (flag & 0x04) &&
1413 (liter->uudet == UU_ENCODED || liter->uudet == XX_ENCODED))
1414 flag |= 2;
1415
1416 /*
1417 * Set the parts we have and/or missing
1418 */
1419
1420 _FP_free (liter->haveparts);
1421 _FP_free (liter->misparts);
1422
1423 liter->haveparts = NULL;
1424 liter->misparts = NULL;
1425
1426 if (havecount) {
1427 if ((liter->haveparts=(int*)malloc((havecount+1)*sizeof(int)))!=NULL) {
1428 memcpy (liter->haveparts, haveparts, havecount*sizeof(int));
1429 liter->haveparts[havecount] = 0;
1430 }
1431 }
1432
1433 if (miscount) {
1434 if ((liter->misparts=(int*)malloc((miscount+1)*sizeof(int)))!=NULL) {
1435 memcpy (liter->misparts, misparts, miscount*sizeof(int));
1436 liter->misparts[miscount] = 0;
1437 }
1438 liter->state |= UUFILE_MISPART;
1439 }
1440
1441 /*
1442 * Finalize checking
1443 */
1444
1445 if ((flag & 4) == 0) liter->state |= UUFILE_NODATA;
1446 if ((flag & 1) == 0) liter->state |= UUFILE_NOBEGIN;
1447 if ((flag & 2) == 0) liter->state |= UUFILE_NOEND;
1448
1449 if ((flag & 7) == 7 && miscount==0) {
1450 liter->state = UUFILE_OK;
1451 }
1452
1453 if ((uu_fast_scanning && (liter->flags&FL_PROPER)==0) || thesize<=0)
1454 liter->size = -1;
1455 else
1456 liter->size = thesize;
1457
1458 if (liter->state==UUFILE_OK &&
1459 (liter->filename==NULL || liter->filename[0]=='\0')) {
1460 /*
1461 * Emergency backup if the file does not have a filename
1462 */
1463 _FP_free (liter->filename);
1464 if (liter->subfname && liter->subfname[0] &&
1465 _FP_strpbrk (liter->subfname, "()[];: ") == NULL)
1466 liter->filename = _FP_strdup (liter->subfname);
1467 else {
1468 sprintf (uucheck_tempname, "%s.%03d", nofname, ++nofnum);
1469 liter->filename = _FP_strdup (uucheck_tempname);
1470 }
1471 }
1472 liter = liter->NEXT;
1473 }
1474
1475 /*
1476 * Sets back (PREV) links
1477 */
1478
1479 liter = UUGlobalFileList;
1480 prev = NULL;
1481
1482 while (liter) {
1483 liter->PREV = prev;
1484 prev = liter;
1485 liter = liter->NEXT;
1486 }
1487
1488 return UUGlobalFileList;
1489 }
1490