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