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