1 /*
2  *  RNtrack - FTN message tracker/router
3  *
4  *  attach.cpp - Work with attaches
5  *
6  *  Copyright (c) 2003-2005 Alex Soukhotine, 2:5030/1157
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  $Id: attach.cpp 257 2020-01-30 18:19:33Z dukelsky $
14  */
15 
16 #include "compiler.h"
17 #ifdef HAVE_CONFIG_H
18     #include "aconfig.h"
19 #endif
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #ifdef HAVE_UNISTD_H
24     #include <unistd.h>
25 #endif
26 #ifdef HAVE_DOS_H
27     #include <dos.h>
28 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include "string.hpp"
32 #include <ctype.h>
33 #ifdef HAVE_FCNTL_H
34     #include <fcntl.h>
35 #endif
36 #include <errno.h>
37 #include "constant.hpp"
38 #include "help.hpp"
39 #include "utils.hpp"
40 #include "vars.hpp"
41 #include "configure.hpp"
42 #include "fidoaddr.hpp"
43 #include "scandir.hpp"
44 #include "attach.hpp"
45 #include "outbound.hpp"
46 #include "mytypes.hpp"
47 #include "msg.hpp"
48 #if defined(HAS_IO_H) || defined(HAVE_IO_H)
49     #include <io.h>
50 #endif
51 
52 #ifdef __WATCOMC__
53     #undef far
54 #endif
55 
56 #ifdef __NT__
57     #undef byte
58     #undef EXPENTRY
59     #include <windows.h>
60 #endif
61 
62 // --------------------------------------------------------------------
63 static char NewPath[BUFF_SIZE];
64 static char NewSubj[73];
65 static int AttSize;
66 static char FboxPath[BUFF_SIZE];
67 // --------------------------------------------------------------------
68 
BaseName(char * name)69 static char * BaseName(char * name)
70 {
71     static char Buff[BUFF_SIZE];
72     char Buff1[BUFF_SIZE];
73     char * tmt;
74 
75     Buff[0] = '\0';
76     RSTRLCPY(Buff1, name, BUFF_SIZE);
77 
78     if((tmt = strrchr(Buff1, PATHDELIMC)) != NULL)
79     {
80         tmt++;
81         RSTRLCPY(Buff1, tmt, BUFF_SIZE);
82     }
83 
84     if((tmt = strrchr(Buff1, ':')) != NULL)
85     {
86         tmt++;
87         RSTRLCPY(Buff1, tmt, BUFF_SIZE);
88     }
89 
90     if((tmt = strrchr(Buff1, '/')) != NULL)
91     {
92         tmt++;
93         RSTRLCPY(Buff1, tmt, BUFF_SIZE);
94     }
95 
96     if((tmt = strrchr(Buff1, '\\')) != NULL)
97     {
98         tmt++;
99         RSTRLCPY(Buff1, tmt, BUFF_SIZE);
100     }
101 
102     RSTRLCAT(Buff, Buff1, BUFF_SIZE);
103     return Buff;
104 } // BaseName
105 
FullName(char * name)106 static char * FullName(char * name)
107 {
108     static char Buff[BUFF_SIZE];
109 
110     if(FileInbound != NULL)
111     {
112         RSTRLCPY(Buff, FileInbound, BUFF_SIZE);
113     }
114     else
115     {
116         Buff[0] = '\0';
117     }
118 
119     if((strchr(name, PATHDELIMC) == NULL
120 #ifndef __unix__
121             && strchr(name, ':') == NULL
122 #endif
123        ) || (IgnoreAttachPath != FALSE))
124     {
125         RSTRLCAT(Buff, BaseName(name), BUFF_SIZE);
126     }
127     else
128     {
129         RSTRLCPY(Buff, name, BUFF_SIZE);
130     }
131 
132     return Buff;
133 } // FullName
134 
_PrintAttach(char * Buff)135 int _PrintAttach(char * Buff)
136 {
137     Log.Level(LOGI) << "Attached '" << FullName(Buff) << "'" << EOL;
138     return TRUE;
139 }
140 
_AttToSize(char * Buff)141 int _AttToSize(char * Buff)
142 {
143     int i;
144     int fh;
145     char * tmt;
146 
147     tmt = FullName(Buff);
148 #ifdef __NT__
149     OemToChar(tmt, tmt);
150 #endif
151     fh = open(tmt, O_RDONLY | O_BINARY);
152 #ifdef __NT__
153     CharToOem(tmt, tmt);
154 #endif
155     i = errno;
156 
157     if(fh == -1)
158     {
159         if(i != ENOENT)
160         {
161             Log.Level(LOGE) << "   Unable to open file: '" << tmt <<
162                             "', Errno: " << i << EOL;
163             return FALSE;
164         }
165         else
166         {
167             return TRUE;
168         }
169     }
170 
171     i = filelength(fh);
172 
173     if(i == -1)
174     {
175         i = errno;
176         close(fh);
177         Log.Level(LOGE) << "   Unable to get size of file: '" << tmt <<
178                         "', Errno: " << i << EOL;
179         return FALSE;
180     }
181 
182     close(fh);
183     AttSize += i;
184     return TRUE;
185 } // _AttToSize
186 
_AddToLo(char * Buff)187 int _AddToLo(char * Buff)
188 {
189     char tmt[BUFF_SIZE];
190 
191     tmt[0] = NewPath[0];
192     tmt[1] = '\0';
193 
194     RSTRLCAT(tmt, FullName(Buff), BUFF_SIZE);
195 
196     AddToLo(tmt);
197     return TRUE;
198 }
199 
_AddToFboxLo(char * Buff)200 int _AddToFboxLo(char * Buff)
201 {
202     char tmt[BUFF_SIZE];
203 
204     tmt[0] = NewPath[0];
205     tmt[1] = '\0';
206 
207     if(FboxPath[0] != '\0')
208     {
209         RSTRLCAT(tmt, FboxPath, BUFF_SIZE);
210 
211         if(tmt[strlen(tmt) - 1] != PATHDELIMC)
212         {
213             RSTRLCAT(tmt, PATHDELIMS, BUFF_SIZE);
214         }
215 
216         RSTRLCAT(tmt, BaseName(Buff), BUFF_SIZE);
217     }
218     else
219     {
220         RSTRLCAT(tmt, FullName(Buff), BUFF_SIZE);
221     }
222 
223     AddToLo(tmt);
224     return TRUE;
225 }
226 
_DelFromLo(char * Buff)227 int _DelFromLo(char * Buff)
228 {
229     DelFromLo(FullName(Buff));
230     return TRUE;
231 }
232 
_ChangePath(char * Buff)233 int _ChangePath(char * Buff)
234 {
235     RSTRLCAT(NewSubj, NewPath, 72);
236     RSTRLCAT(NewSubj, BaseName(Buff), 72);
237     RSTRLCAT(NewSubj, " ", 72);
238     return TRUE;
239 }
240 
_ToLowerPath(char * Buff)241 int _ToLowerPath(char * Buff)
242 {
243     char Buff1[BUFF_SIZE];
244 
245     RSTRLCPY(Buff1, Buff, BUFF_SIZE);
246 
247     for(unsigned int i = 0; i < strlen(Buff1); i++)
248     {
249         Buff1[i] = tolower(Buff1[i]);
250     }
251     RSTRLCAT(NewSubj, Buff1, 72);
252     RSTRLCAT(NewSubj, " ", 72);
253     return TRUE;
254 }
255 
_ToUpperPath(char * Buff)256 int _ToUpperPath(char * Buff)
257 {
258     char Buff1[BUFF_SIZE];
259 
260     RSTRLCPY(Buff1, Buff, BUFF_SIZE);
261 
262     for(unsigned int i = 0; i < strlen(Buff1); i++)
263     {
264         Buff1[i] = toupper(Buff1[i]);
265     }
266     RSTRLCAT(NewSubj, Buff1, 72);
267     RSTRLCAT(NewSubj, " ", 72);
268     return TRUE;
269 }
270 
_DeleteAttach(char * Buff)271 int _DeleteAttach(char * Buff)
272 {
273     char * tmt;
274 
275     tmt = FullName(Buff);
276 #ifdef __NT__
277     OemToChar(tmt, tmt);
278 #endif
279 
280     if(access(tmt, F_OK) != 0)
281     {
282 #ifdef __NT__
283         CharToOem(tmt, tmt);
284 #endif
285         Log.Level(LOGI) << "   File not found: '" << tmt << "'" << EOL;
286         return TRUE;
287     }
288 
289     if(unlink(tmt) != 0)
290     {
291 #ifdef __NT__
292         CharToOem(tmt, tmt);
293 #endif
294         Log.Level(LOGE) << "   Unable to delete: '" << tmt << "'" << EOL;
295         return FALSE;
296     }
297 
298 #ifdef __NT__
299     CharToOem(tmt, tmt);
300 #endif
301     Log.Level(LOGI) << "   Delete: '" << tmt << "'" << EOL;
302     return TRUE;
303 } // _DeleteAttach
304 
_AttachExists(char * Buff)305 int _AttachExists(char * Buff)
306 {
307     struct stat dd;
308     char * tmt;
309 
310     tmt = FullName(Buff);
311 #ifdef __NT__
312     OemToChar(tmt, tmt);
313 #endif
314 
315     if(stat(tmt, &dd) != 0)
316     {
317         return FALSE;
318     }
319 
320     if(!S_ISREG(dd.st_mode))
321     {
322         return FALSE;
323     }
324 
325 #if defined (__MINGW32__) || defined (_MSC_VER)
326 
327     if(SkipHiddenFiles)
328     {
329         struct _finddata_t fd;
330         int h = (int)_findfirst(tmt, &fd);
331 
332         if(h != -1)
333         {
334             _findclose(h);
335 
336             if(!strcmp(fd.name, tmt) && (fd.attrib | _A_HIDDEN))
337             {
338                 return FALSE;
339             }
340         }
341     }
342 
343 #elif defined (__DJGPP__)
344 
345     if(SkipHiddenFiles)
346     {
347         unsigned int attrs;
348         _dos_getfileattr(tmt, &attrs);
349 
350         if(attrs | _A_HIDDEN)
351         {
352             return FALSE;
353         }
354     }
355 
356 #elif !defined (__unix__)
357 
358     if(SkipHiddenFiles && (dd.st_attr & 2))
359     {
360         return FALSE;
361     }
362 
363 #endif // if defined (__MINGW32__) || defined (_MSC_VER)
364     return TRUE;
365 } // _AttachExists
366 
_MoveAttach(char * Buff)367 int _MoveAttach(char * Buff)
368 {
369     char * tmt;
370     char B[BUFF_SIZE];
371 
372     tmt = FullName(Buff);
373 #ifdef __NT__
374     OemToChar(tmt, tmt);
375 #endif
376 
377     if(access(tmt, F_OK) != 0)
378     {
379 #ifdef __NT__
380         CharToOem(tmt, tmt);
381 #endif
382         Log.Level(LOGI) << "   File not found: '" << tmt << "'" << EOL;
383         return TRUE;
384     }
385 
386     RSTRLCPY(B, NewPath, BUFF_SIZE);
387     RSTRLCAT(B, BaseName(Buff), BUFF_SIZE);
388     tmt = FullName(Buff);
389 #ifdef __NT__
390     OemToChar(tmt, tmt);
391     OemToChar(B, B);
392 #endif
393 
394     if(!FileMove(B, tmt))
395     {
396 #ifdef __NT__
397         CharToOem(tmt, tmt);
398 #endif
399         Log.Level(LOGE) << "   Unable to move file '" << tmt << "' to " <<
400                         NewPath << EOL;
401         return FALSE;
402     }
403 
404 #ifdef __NT__
405     CharToOem(tmt, tmt);
406 #endif
407     Log.Level(LOGI) << "   Move: '" << tmt << "' ==> " << NewPath << EOL;
408     return TRUE;
409 } // _MoveAttach
410 
_CopyAttach(char * Buff)411 int _CopyAttach(char * Buff)
412 {
413     char * tmt;
414     char B[BUFF_SIZE];
415 
416     tmt = FullName(Buff);
417 #ifdef __NT__
418     OemToChar(tmt, tmt);
419 #endif
420 
421     if(access(tmt, F_OK) != 0)
422     {
423 #ifdef __NT__
424         CharToOem(tmt, tmt);
425 #endif
426         Log.Level(LOGI) << "   File not found: '" << tmt <<
427                         "', can't copy." << EOL;
428         return TRUE;
429     }
430 
431     RSTRLCPY(B, NewPath, BUFF_SIZE);
432     RSTRLCAT(B, BaseName(Buff), BUFF_SIZE);
433     tmt = FullName(Buff);
434 #ifdef __NT__
435     OemToChar(tmt, tmt);
436     OemToChar(B, B);
437 #endif
438 
439     if(!FileCopy(B, tmt))
440     {
441 #ifdef __NT__
442         CharToOem(tmt, tmt);
443 #endif
444         Log.Level(LOGE) << "   Unable to copy file '" << tmt << "' to " <<
445                         NewPath << EOL;
446         return FALSE;
447     }
448 
449 #ifdef __NT__
450     CharToOem(tmt, tmt);
451 #endif
452     Log.Level(LOGI) << "   Copy: '" << tmt << "' ==> " << NewPath << EOL;
453     return TRUE;
454 } // _CopyAttach
455 
456 // --------------------------------------------------------------------
457 #if defined (__unix__) || defined (__EMX__)
458 
459 typedef int (*faff)(char * b);
460 
ForAllFiles(faff Action,cMSG & m)461 int ForAllFiles(faff Action, cMSG & m)
462 {
463 #else
464 int ForAllFiles(int (* Action)(char * Fname), cMSG & m)
465 {
466 #endif
467 // For all Files attached to message do Action.
468 // return Action value.
469 // Action - int Action(char *FName);
470     char Buff[73];
471     char * tmt;
472 
473     if(strlen(m._Subject) == 0)
474     {
475         return FALSE;
476     }
477 
478     memset(Buff, 0, 73);
479     RSTRLCPY(Buff, m._Subject, 72);
480     tmt = Buff;
481 
482     while(*tmt == ' ')
483     {
484         tmt++;
485     }
486 
487     if(*tmt == '\0')
488     {
489         return FALSE;
490     }
491 
492     while(*tmt != '\0')
493     {
494         while(*tmt == ' ')
495         {
496             tmt++;
497         }
498 
499         if(*tmt == '\0')
500         {
501             break;
502         }
503 
504         int i;
505         i = FALSE;
506 
507         if(strchr(tmt, ' ') != NULL)
508         {
509             i = TRUE;
510             *strchr(tmt, ' ') = '\0';
511         }
512 
513         if(!Action(tmt))
514         {
515             return FALSE;
516         }
517 
518         while(*tmt != '\0')
519         {
520             tmt++;
521         }
522 
523         if(i)
524         {
525             tmt++;
526         }
527     }
528     return TRUE;
529 } // ForAllFiles
530 
531 // --------------------------------------------------------------------
532 
533 int PrintAttach(cMSG & m)
534 {
535     return ForAllFiles(&_PrintAttach, m);
536 }
537 
538 int AddAttachToLo(cMSG & m)
539 {
540     NewPath[0] = '\0';
541 
542     if(m.fTFS)
543     {
544         NewPath[0] = '#';
545     }
546 
547     if(m.fKFS)
548     {
549         NewPath[0] = '^';
550     }
551 
552     return ForAllFiles(&_AddToLo, m);
553 }
554 
555 int AddFboxAttachToLo(cMSG & m, char * path)
556 {
557     NewPath[0] = '\0';
558 
559     if(m.fTFS)
560     {
561         NewPath[0] = '#';
562     }
563 
564     if(m.fKFS)
565     {
566         NewPath[0] = '^';
567     }
568 
569     RSTRLCPY(FboxPath, path, BUFF_SIZE);
570     return ForAllFiles(&_AddToFboxLo, m);
571 }
572 
573 int DelAttachFromLo(cMSG & m)
574 {
575     return ForAllFiles(&_DelFromLo, m);
576 }
577 
578 int DeleteAttach(cMSG & m)
579 {
580     return ForAllFiles(&_DeleteAttach, m);
581 }
582 
583 int ChangePath(cMSG & m, char * Path)
584 {
585     int rc;
586 
587     RSTRLCPY(NewPath, Path, BUFF_SIZE);
588     memset(NewSubj, 0, 73);
589 
590     if(strlen(NewPath) != 0 && NewPath[strlen(NewPath) - 1] != PATHDELIMC)
591     {
592         RSTRLCAT(NewPath, PATHDELIMS, BUFF_SIZE);
593     }
594 
595     rc = ForAllFiles(&_ChangePath, m);
596 
597     if(!rc)
598     {
599         return FALSE;
600     }
601 
602     if(NewSubj[0] != '\0')
603     {
604         NewSubj[strlen(NewSubj) - 1] = '\0';
605     }
606 
607     if(strlen(NewSubj) > 71)
608     {
609         Log.Level(LOGE) << "New subject too long. '" << NewSubj << "'" << EOL;
610         return FALSE;
611     }
612 
613     RSTRLCPY(m._Subject, NewSubj, 72);
614     return TRUE;
615 } // ChangePath
616 
617 int ToLowerPath(cMSG & m)
618 {
619     int rc;
620 
621     memset(NewSubj, 0, 73);
622     rc = ForAllFiles(&_ToLowerPath, m);
623 
624     if(!rc)
625     {
626         return FALSE;
627     }
628 
629     if(NewSubj[0] != '\0')
630     {
631         NewSubj[strlen(NewSubj) - 1] = '\0';
632     }
633 
634     if(strlen(NewSubj) > 71)
635     {
636         Log.Level(LOGE) << "New subject too long. '" << NewSubj << "'" << EOL;
637         return FALSE;
638     }
639 
640     RSTRLCPY(m._Subject, NewSubj, 72);
641     return TRUE;
642 }
643 
644 int ToUpperPath(cMSG & m)
645 {
646     int rc;
647 
648     memset(NewSubj, 0, 73);
649     rc = ForAllFiles(&_ToUpperPath, m);
650 
651     if(!rc)
652     {
653         return FALSE;
654     }
655 
656     if(NewSubj[0] != '\0')
657     {
658         NewSubj[strlen(NewSubj) - 1] = '\0';
659     }
660 
661     if(strlen(NewSubj) > 71)
662     {
663         Log.Level(LOGE) << "New subject too long. '" << NewSubj << "'" << EOL;
664         return FALSE;
665     }
666 
667     RSTRLCPY(m._Subject, NewSubj, 72);
668     return TRUE;
669 }
670 
671 int GetAttSize(cMSG & m)
672 {
673     int rc;
674 
675     AttSize = 0;
676     rc = ForAllFiles(&_AttToSize, m);
677 
678     if(!rc)
679     {
680         return -1;
681     }
682 
683     return AttSize;
684 }
685 
686 int MoveAttach(cMSG & m, char * Path)
687 {
688     int rc;
689 
690     RSTRLCPY(NewPath, Path, BUFF_SIZE);
691     memset(NewSubj, 0, 73);
692 
693     if(strlen(NewPath) != 0 && NewPath[strlen(NewPath) - 1] != PATHDELIMC)
694     {
695         RSTRLCAT(NewPath, PATHDELIMS, BUFF_SIZE);
696     }
697 
698     rc = ForAllFiles(&_ChangePath, m);
699 
700     if(!rc)
701     {
702         return FALSE;
703     }
704 
705     if(NewSubj[0] != '\0')
706     {
707         NewSubj[strlen(NewSubj) - 1] = '\0';
708     }
709 
710     if(strlen(NewSubj) > 71)
711     {
712         Log.Level(LOGE) << "New subject too long. '" << NewSubj << "'" << EOL;
713         return FALSE;
714     }
715 
716     rc = ForAllFiles(&_MoveAttach, m);
717 
718     if(!rc)
719     {
720         return FALSE;
721     }
722 
723 //   strncpy(m._Subject,NewSubj,72);
724     return TRUE;
725 } // MoveAttach
726 
727 int CopyAttach(cMSG & m, char * Path)
728 {
729     int rc;
730 
731     RSTRLCPY(NewPath, Path, BUFF_SIZE);
732 
733     if(strlen(NewPath) != 0 && NewPath[strlen(NewPath) - 1] != PATHDELIMC)
734     {
735         RSTRLCAT(NewPath, PATHDELIMS, BUFF_SIZE);
736     }
737 
738     rc = ForAllFiles(&_CopyAttach, m);
739 
740     if(!rc)
741     {
742         return FALSE;
743     }
744 
745     return TRUE;
746 }
747 
748 int AttachExists(cMSG & m)
749 {
750     return ForAllFiles(&_AttachExists, m);
751 }
752 
753 // --------------------------------------------------------------------
754 int SetFileInbound(char * tmt)
755 {
756     IndBiList<ScanDir>::ElemPtr sd;
757     size_t size;
758 
759     sd = ScanDirs.GetLast();
760 
761     if(sd == NULL)
762     {
763         if(FileInbound != NULL)
764         {
765             yyerror("File inbound directory already defined.");
766             return -1;
767         }
768     }
769     else
770     {
771         if(sd->_FileInbound != NULL)
772         {
773             yyerror("File inbound directory for this scandir already defined.");
774             return -1;
775         }
776     }
777 
778     if(strlen(tmt) == 0)
779     {
780         yyerror("Missing parameter: Inbound directory name.");
781         return -1;
782     }
783 
784     if(!DirExists(tmt))
785     {
786         yyerror("Unable to open file inbound directory.");
787         return -1;
788     }
789 
790     size = strlen(tmt) + 2;
791 
792     if(sd == NULL)
793     {
794         FileInbound = (char *)malloc(size);
795         CheckMem(FileInbound);
796         RSTRLCPY(FileInbound, tmt, size);
797 
798         if(FileInbound[strlen(FileInbound) - 1] != PATHDELIMC)
799         {
800             RSTRLCAT(FileInbound, PATHDELIMS, size);
801         }
802     }
803     else
804     {
805         sd->_FileInbound = (char *)malloc(size);
806         CheckMem(sd->_FileInbound);
807         RSTRLCPY(sd->_FileInbound, tmt, size);
808 
809         if(FileInbound[strlen(sd->_FileInbound) - 1] != PATHDELIMC)
810         {
811             RSTRLCAT(sd->_FileInbound, PATHDELIMS, size);
812         }
813     }
814 
815     return 0;
816 } // SetFileInbound
817 
818 int SetSkipHiddenFiles(void)
819 {
820     if(SkipHiddenFiles)
821     {
822         yyerror("SkipHiddenFiles already set.");
823         return -1;
824     }
825 
826     SkipHiddenFiles = TRUE;
827     return 0;
828 }
829 
830 // ---------------------------- END --------------------------------------
831