1 /**********************************************************
2 * ftn tools
3 **********************************************************/
4 /*
5 * $Id: ftn.c,v 1.10 2005/08/18 16:21:25 mitry Exp $
6 *
7 * $Log: ftn.c,v $
8 * Revision 1.10 2005/08/18 16:21:25 mitry
9 * Added debug messages
10 *
11 * Revision 1.9 2005/08/10 19:19:30 mitry
12 * Changed strncasecmp() to strcasecmp() in whattype()
13 *
14 * Revision 1.8 2005/05/16 11:17:30 mitry
15 * Updated function prototypes. Changed code a bit.
16 *
17 * Revision 1.7 2005/05/11 20:18:26 mitry
18 * Cosmetic change
19 *
20 * Revision 1.6 2005/05/06 20:34:09 mitry
21 * whattype() is slightly changed.
22 * Misc code cleanup.
23 *
24 * Revision 1.5 2005/03/28 17:02:52 mitry
25 * Pre non-blocking i/o update. Mostly non working.
26 *
27 */
28
29 #include "headers.h"
30 #include <fnmatch.h>
31 #include "crc.h"
32
33 /* domain name to translate ftn address to inet host. */
34 #define FTNDOMAIN "binkp.net"
35
36
addr_cpy(ftnaddr_t * a,const ftnaddr_t * b)37 void addr_cpy(ftnaddr_t *a, const ftnaddr_t *b)
38 {
39 if ( !a || !b )
40 return;
41 a->z = b->z;
42 a->n = b->n;
43 a->f = b->f;
44 a->p = b->p;
45 if ( b->d && *b->d )
46 a->d = xstrdup( b->d );
47 else
48 a->d = NULL;
49 }
50
51
addr_cmp(const ftnaddr_t * a,const ftnaddr_t * b)52 int addr_cmp(const ftnaddr_t *a, const ftnaddr_t *b)
53 {
54 if ( !a || !b )
55 return 0;
56
57 return ( a->z == b->z && a->n == b->n
58 && a->f == b->f && a->p == b->p ) ? 1 : 0;
59 }
60
61
parseftnaddr(const char * s,ftnaddr_t * a,const ftnaddr_t * b,int wc)62 int parseftnaddr(const char *s, ftnaddr_t *a, const ftnaddr_t *b, int wc)
63 {
64 const char *p = s, *pn;
65 int n = -1, wn = 0, pq = 1;
66
67 if(!s||!*s)return 0;
68 if(b) {
69 addr_cpy(a,b);
70 a->p=wc?-1:0;
71 } else a->z=a->n=a->f=a->p=wc?-1:0,a->d=NULL;
72 for(pn=p;*p&&pq;p++) {
73 if(isdigit((int)*p))wn=1;
74 else if(wc&&*p=='*')wn=2;
75 else switch(*p) {
76 case ':':
77 if(!wn||n>0)return 0;
78 a->z=(wn<2)?atoi(pn):-1;
79 pn=p+1;wn=0;n=1;
80 break;
81 case '/':
82 if(!wn||n>1)return 0;
83 a->n=(wn<2)?atoi(pn):-1;
84 n=2;pn=p+1;wn=0;
85 break;
86 case '.':
87 if(n>2)return 0;
88 if(wn)a->f=(wn<2)?atoi(pn):-1;
89 n=3;pn=p+1;
90 if(!wn&&n<0)break;
91 if(!wn)return 0;
92 wn=0;
93 break;
94 case '@':
95 if(p[1]) {
96 xfree(a->d);
97 a->d=xstrdup(p+1);
98 }
99 case '\n': case '\r':
100 case ' ': case '\t':
101 case '\0':
102 pq=0;
103 break;
104 default:return 0;
105 }
106 }
107 switch(n) {
108 case 2:
109 if(!wn)return 0;
110 a->f=(wn<2)?atoi(pn):-1;
111 break;
112 case 3:
113 if(!wn)return 0;
114 a->p=(wn<2)?atoi(pn):-1;
115 break;
116 case -1:
117 if(!wn)return 0;
118 a->f=(wn<2)?atoi(pn):-1;
119 break;
120 default:
121 return 0;
122 }
123 return 1;
124 }
125
126
akamatch(const ftnaddr_t * a,falist_t * akas)127 ftnaddr_t *akamatch(const ftnaddr_t *a, falist_t *akas)
128 {
129 int m,bm=0;
130 falist_t *i;
131 ftnaddr_t *best=&akas->addr;
132 for(i=akas;i;i=i->next) {
133 m=0;
134 if(i->addr.z==a->z) {
135 m=1;
136 if(i->addr.n==a->n) {
137 m=2;
138 if(i->addr.f==a->f) {
139 m=3;
140 if(i->addr.p==a->p)m=4;
141 }
142 }
143 }
144 if(m>bm) {
145 bm=m;
146 best=&i->addr;
147 }
148 }
149 return best;
150 }
151
ftnaddrtoa(const ftnaddr_t * a)152 char *ftnaddrtoa(const ftnaddr_t *a)
153 {
154 static char s[30];
155 if(a->p)snprintf(s,30,"%d:%d/%d.%d",a->z,a->n,a->f,a->p);
156 else snprintf(s,30,"%d:%d/%d",a->z,a->n,a->f);
157 return s;
158 }
159
ftnaddrtoda(const ftnaddr_t * a)160 char *ftnaddrtoda(const ftnaddr_t *a)
161 {
162 char *d=cfgs(CFG_DOMAIN);
163 static char s[64];
164 if(!*d)d="fidonet.org";
165 if(*d=='@')d++;
166 if(a->p)snprintf(s,64,"%d:%d/%d.%d@%s",a->z,a->n,a->f,a->p,a->d?a->d:d);
167 else snprintf(s,64,"%d:%d/%d@%s",a->z,a->n,a->f,a->d?a->d:d);
168 return s;
169 }
170
ftnaddrtoia(const ftnaddr_t * a)171 char *ftnaddrtoia(const ftnaddr_t *a)
172 {
173 static char s[64];
174 if(a->p)snprintf(s,64,"p%d.f%d.n%d.z%d." FTNDOMAIN,a->p,a->f,a->n,a->z);
175 else snprintf(s,64,"f%d.n%d.z%d." FTNDOMAIN,a->f,a->n,a->z);
176 return s;
177 }
178
strip8(char * s)179 char *strip8(char *s)
180 {
181 register int t, i = 0;
182 static char buf[MAX_STRING + 5];
183
184 if ( !s )
185 return NULL;
186
187 if ( *s )
188 recode_to_remote( s );
189
190 while( *s && i < MAX_STRING) {
191 t = *s;
192 if ( t == '}' || t == ']' ) {
193 if ( !bink ) {
194 buf[i++] = t;
195 buf[i] = t;
196 }
197 } else if ( isprint( t ))
198 buf[i] = t;
199 else {
200 buf[i++] = '\\';
201 buf[i++] = hexdigitsupper[(t >> 4) & 0x0f];
202 buf[i] = hexdigitsupper[t & 0x0f];
203 }
204 i++;
205 s++;
206 }
207
208 buf[i] = '\0';
209 return xstrdup( buf );
210 }
211
212
has_addr(const ftnaddr_t * a,falist_t * l)213 int has_addr(const ftnaddr_t *a, falist_t *l)
214 {
215 while(l) {
216 if(addr_cmp(a,&l->addr))return 1;
217 l=l->next;
218 }
219 return 0;
220 }
221
showpkt(const char * fn)222 int showpkt(const char *fn)
223 {
224 FILE *f;
225 int i,n=1;
226 pkthdr_t ph;
227 pktmhdr_t mh;
228 char from[36],to[36],a;
229 f=fopen(fn,"r");
230 if(!f){write_log("can't open '%s' for reading: %s",fn,strerror(errno));return 0;}
231 if(fread(&ph,sizeof(ph),1,f)!=1)write_log("packet read error");
232 else if(I2H16(ph.phType)!=2)write_log("packet isn't 2+ format");
233 else {
234 while(fread(&mh,sizeof(mh),1,f)==1) {
235 i=0;while(fgetc(f)>0&&i<30)i++;i=0;
236 if(i>=30)break;
237 while((a=fgetc(f))>0&&i<36)to[i++]=a;
238 if(i>=36)break;
239 to[i]=0;i=0;
240 while((a=fgetc(f))>0&&i<36)from[i++]=a;
241 if(i>=32)break;
242 from[i]=0;i=0;
243 while(fgetc(f)>0&&i<72)i++;
244 if(i>=72)break;
245 while(fgetc(f)>0);
246 write_log("*msg: %d from: \"%s\", to: \"%s\"",n++,from,to);
247 }
248 }
249 fclose(f);
250 return 0;
251 }
252
openpktmsg(const ftnaddr_t * fa,const ftnaddr_t * ta,char * from,char * to,char * subj,char * pwd,char * fn,unsigned attr)253 FILE *openpktmsg(const ftnaddr_t *fa, const ftnaddr_t *ta,
254 char *from, char *to, char *subj, char *pwd, char *fn, unsigned attr)
255 {
256 FILE *f;
257 pkthdr_t ph;
258 pktmhdr_t mh;
259 time_t tim=time(NULL);
260 struct tm *t=localtime(&tim);
261 if(!(f=fopen(fn,"w")))return NULL;
262 memset(&ph,0,sizeof(ph));
263 memset(&mh,0,sizeof(mh));
264 ph.phONode=H2I16(fa->f);
265 ph.phDNode=H2I16(ta->f);
266 ph.phONet=H2I16(fa->n);
267 ph.phDNet=H2I16(ta->n);
268 ph.phYear=H2I16(t->tm_year+1900);
269 ph.phMonth=H2I16(t->tm_mon);
270 ph.phDay=H2I16(t->tm_mday);
271 ph.phHour=H2I16(t->tm_hour);
272 ph.phMinute=H2I16(t->tm_min);
273 ph.phSecond=H2I16(t->tm_sec);
274 ph.phBaud=H2I16(0);
275 ph.phPCode=0xFE;
276 ph.phType=H2I16(2);
277 ph.phAuxNet=H2I16(0);
278 ph.phCWValidate=H2I16(0x100);
279 ph.phPCodeHi=1;
280 ph.phPRevMinor=2;
281 ph.phCaps=H2I16(1);
282 if(pwd)memcpy(ph.phPass,pwd,MAX(strlen(pwd),8));
283 ph.phQOZone=H2I16(fa->z);
284 ph.phQDZone=H2I16(ta->z);
285 ph.phOZone=H2I16(fa->z);
286 ph.phDZone=H2I16(ta->z);
287 ph.phOPoint=H2I16(fa->p);
288 ph.phDPoint=H2I16(ta->p);
289 fwrite(&ph,sizeof(ph),1,f);
290 mh.pmONode=H2I16(fa->f);
291 mh.pmDNode=H2I16(ta->f);
292 mh.pmONet=H2I16(fa->n);
293 mh.pmDNet=H2I16(ta->n);
294 mh.pmAttr=H2I16(attr);
295 mh.pmType=H2I16(2);
296 fwrite(&mh,sizeof(mh),1,f);
297 fprintf(f,"%02d %3s %02d %02d:%02d:%02d%c",t->tm_mday,engms[t->tm_mon],t->tm_year%100,t->tm_hour,t->tm_min,t->tm_sec,0);
298 if(cfgi(CFG_RECODEPKTS)) {
299 recode_to_remote(to);
300 if(attr<128) {
301 recode_to_remote(subj);
302 recode_to_remote(from);
303 }
304 }
305 fwrite(to,strlen(to)+1,1,f);
306 fwrite(from,strlen(from)+1,1,f);
307 fwrite(subj,strlen(subj)+1,1,f);
308 fprintf(f,"\001INTL %d:%d/%d %d:%d/%d\r",ta->z,ta->n,ta->f,fa->z,fa->n,fa->f);
309 if(fa->p)fprintf(f,"\001FMPT %d\r",fa->p);
310 if(ta->p)fprintf(f,"\001TOPT %d\r",ta->p);
311 fprintf(f,"\001MSGID: %s %08lx\r",ftnaddrtoa(fa),sequencer());
312 fprintf(f,"\001PID: %s %s/%s\r",progname,version,osname);
313 return f;
314 }
315
closepkt(FILE * f,const ftnaddr_t * fa,const char * tear,char * orig)316 void closepkt(FILE *f, const ftnaddr_t *fa, const char *tear, char *orig)
317 {
318 if(cfgi(CFG_RECODEPKTS))recode_to_remote(orig);
319 fprintf(f,"--- %s\r * Origin: %s (%s)\r%c%c%c",tear,orig,ftnaddrtoa(fa),0,0,0);
320 fclose(f);
321 }
322
323
closeqpkt(FILE * f,const ftnaddr_t * fa)324 void closeqpkt(FILE *f, const ftnaddr_t *fa)
325 {
326 char str[MAX_STRING+1];
327
328 snprintf( str, MAX_STRING, "%s-%s/%s", qver( 0 ), qver( 1 ), qver( 2 ));
329 closepkt( f, fa, str, cfgs( CFG_STATION ));
330 }
331
332
whattype(const char * fn)333 int whattype(const char *fn)
334 {
335 static char *ext[] = {"su","mo","tu","we","th","fr","sa","pkt","req"};
336 register int i;
337 char *p, low;
338
339 if ( !fn )
340 return IS_ERR;
341
342 p = strrchr( fn, '.' );
343 if ( !p )
344 return IS_FILE;
345
346 if ( strlen( ++p ) != 3 )
347 return IS_FILE;
348
349 if ( strcasecmp( p + 1, "lo" ) == 0 )
350 return IS_FLO;
351
352 for( i = 0; i < 9; i++ )
353 if ( !strncasecmp( p, ext[i], strlen( ext[i] )))
354 switch( i ) {
355 case 7: return IS_PKT;
356 case 8: return IS_REQ;
357 default:
358 low = tolower( p[2] );
359 if (( low >= '0' && low <= '9' )
360 || ( low >= 'a' && low <= 'z' ))
361 return IS_ARC;
362 break;
363 }
364 return IS_FILE;
365 }
366
367
istic(const char * fn)368 int istic(const char *fn)
369 {
370 size_t flen;
371
372 if ( !fn || ( flen = strlen( fn )) < 4 )
373 return 0;
374
375 return ( strncasecmp( fn + flen - 4, ".tic", 4 ) == 0 );
376 }
377
378
havestatus(int status,int cfgkey)379 int havestatus(int status, int cfgkey)
380 {
381 static int stc[] = { Q_NORM, Q_HOLD, Q_DIR, Q_CRASH, Q_IMM, Q_REQ };
382 static char stl[] = Q_CHARS;
383 register int i;
384 char *callon = cfgs( cfgkey );
385
386 for( i = 0; i < F_MAX; i++ )
387 if (( status & stc[i] ) && ( callon && strchr( callon, stl[i] ))) {
388 DEBUG(('Q',1,"havestatus: yes, i %d, callon '%s', status 0x%X",i,callon,status));
389 return 1;
390 }
391 DEBUG(('Q',1,"havestatus: no, callon '%s', status 0x%X",callon,status));
392 return 0;
393 }
394
395
needhold(int status,int what)396 int needhold(int status, int what)
397 {
398 status &= Q_ANYWAIT;
399 if ( status & Q_WAITA ) return 1;
400 if (( status & Q_WAITR ) && !( what & (~T_REQ))) return 1;
401 if (( status & Q_WAITX ) && !( what & (~T_ARCMAIL)))return 1;
402 return 0;
403 }
404
405
xfnmatch(char * pat,const char * name,int flags)406 int xfnmatch(char *pat, const char *name, int flags)
407 {
408 int type,rc=0,q=0;
409 if(!name||!pat)return FNM_NOMATCH;
410 type=whattype(name);
411 if(*pat=='!'){pat++;rc=1;}
412 if(*pat=='%') {
413 switch(pat[1]) {
414 case 'F':
415 if(type==IS_FILE)q=1;
416 break;
417 case 'N':
418 if(type==IS_PKT)q=1;
419 break;
420 case 'E':
421 if(type==IS_ARC)q=1;
422 break;
423 default:
424 write_log("error: mask '%s': unknown macro '%c'",pat-rc,pat[1]);
425 return FNM_NOMATCH;
426 }
427 } else q=!fnmatch(pat,name,flags);
428 DEBUG(('S',4,"xfnm: '%s', pat='%s'. type=%d, q=%d, rc=%d",name,pat,type,q,rc));
429 return((rc^q)?0:FNM_NOMATCH);
430 }
431
432
findpwd(const ftnaddr_t * a)433 char *findpwd(const ftnaddr_t *a)
434 {
435 faslist_t *cf;
436
437 for( cf = cfgfasl( CFG_PASSWORD ); cf; cf = cf->next )
438 if ( addr_cmp( &cf->addr, a ))
439 return cf->str;
440 return NULL;
441 }
442