1 /**********************************************************
2  * Queue operations
3  **********************************************************/
4 /*
5  * $Id: queue.c,v 1.12 2005/08/18 16:11:22 mitry Exp $
6  *
7  * $Log: queue.c,v $
8  * Revision 1.12  2005/08/18 16:11:22  mitry
9  * Extended debug message
10  *
11  * Revision 1.11  2005/06/10 20:49:32  mitry
12  * Updated q_each() to make qico to call a node if we have
13  * empty FLOw file(s) or netmail packet(s) with callable
14  * flavour.
15  *
16  * Revision 1.10  2005/05/16 11:17:30  mitry
17  * Updated function prototypes. Changed code a bit.
18  *
19  * Revision 1.9  2005/05/11 16:44:40  mitry
20  * Changed a bit a call of outbound_rescan()
21  *
22  * Revision 1.8  2005/05/06 20:46:23  mitry
23  * Empty FLOw file in outbound now can make a qico to poll node during mail hours.
24  * Misc code cleanup.
25  *
26  * Revision 1.7  2005/03/31 19:40:38  mitry
27  * Update function prototypes and it's duplication
28  *
29  */
30 
31 #include "headers.h"
32 #include "qipc.h"
33 
34 #define _Z(x) ((qitem_t *)x)
q_cmp(const void * q1,const void * q2)35 int q_cmp(const void *q1, const void *q2)
36 {
37 	if(_Z(q1)->addr.z!=_Z(q2)->addr.z)return _Z(q1)->addr.z-_Z(q2)->addr.z;
38 	if(_Z(q1)->addr.n!=_Z(q2)->addr.n)return _Z(q1)->addr.n-_Z(q2)->addr.n;
39 	if(_Z(q1)->addr.f!=_Z(q2)->addr.f)return _Z(q1)->addr.f-_Z(q2)->addr.f;
40 	return _Z(q1)->addr.p-_Z(q2)->addr.p;
41 }
42 
43 
q_find(const ftnaddr_t * fa)44 qitem_t *q_find(const ftnaddr_t *fa)
45 {
46 	qitem_t	*i;
47 	int	r = 1;
48 
49 	for ( i = q_queue; i && ( r = q_cmp( &i->addr, fa )) < 0 ; i = i->next );
50 	return r ? NULL : i;
51 }
52 
53 
q_add(const ftnaddr_t * fa)54 qitem_t *q_add(const ftnaddr_t *fa)
55 {
56 	qitem_t	**i, *q;
57 	int	r = 1;
58 
59 	for( i = &q_queue; *i && ( r = q_cmp( &(*i)->addr, fa )) < 0 ; i = &((*i)->next ));
60 
61 	if ( !r )
62 		return *i;
63 
64 	q = xcalloc( 1, sizeof( qitem_t ));
65 	q->next = *i;
66 	q->canpoll = 0;
67 	*i = q;
68 	addr_cpy( &q->addr, fa );
69 
70 	return q;
71 }
72 
73 
q_recountflo(const char * name,off_t * size,time_t * mtime,int rslow)74 int q_recountflo(const char *name, off_t *size, time_t *mtime, int rslow)
75 {
76 	FILE		*f;
77 	struct stat	sb;
78 	char		s[MAX_STRING + 5], *p, *m;
79 	off_t		total = 0;
80 	int		fcount = 1;
81 
82 	DEBUG(('Q',4,"scan lo '%s'",name));
83 
84 	if ( !stat( name, &sb )) {
85 		if ( sb.st_mtime != *mtime || rslow ) {
86 			*mtime = sb.st_mtime;
87 			f = fopen( name, "rt" );
88 			if ( f ) {
89 				fcount = 0;
90 				while( fgets( s, MAX_STRING - 1, f )) {
91                                         DEBUG(('Q',5,"scan lo -> '%s'",s));
92 					if ( *s == '~' )
93 						continue;
94 
95 					p = strrchr( s, '\r' );
96 					if ( p )
97 						*p = '\0';
98 					p = strrchr( s, '\n' );
99 					if ( p )
100 						*p = '\0';
101 					p = s;
102 					if ( *p == '^' || *p == '#' )
103 						p++;
104 					m = mappath( p );
105 					if ( *m )
106 						p = m;
107 					if ( !stat( p, &sb ))
108 						total += sb.st_size;
109 					fcount++;
110                                         DEBUG(('Q',5,"%10lu '%s'",(unsigned long) sb.st_size,p));
111 				}
112 				fclose( f );
113 			} else {
114 				write_log( "can't open %s: %s", name, strerror( errno ));
115 			}
116 			*size = total;
117 		} else {
118 			fcount = sb.st_size;
119 		}
120 	} else {
121 		*mtime = 0;
122 		*size = 0;
123 	}
124 
125 	return fcount;
126 }
127 
128 
q_recountbox(const char * name,off_t * size,time_t * mtime,int rslow)129 void q_recountbox(const char *name, off_t *size, time_t *mtime, int rslow)
130 {
131 	DIR		*d;
132 	struct dirent	*de;
133 	struct stat	sb;
134 	char		p[MAX_PATH + 5];
135 	off_t		total = 0;
136 
137 	if ( !stat( name, &sb )
138 		&& (( sb.st_mode & S_IFMT ) == S_IFDIR
139 			|| ( sb.st_mode & S_IFMT ) == S_IFLNK ))
140 	{
141 		if ( sb.st_mtime != *mtime || rslow ) {
142 			DEBUG(('Q',4,"scan box '%s'",name));
143 			*mtime = sb.st_mtime;
144 			d = opendir( name );
145 			if ( d ) {
146 				while(( de = readdir( d ))) {
147 					if ( de->d_name[0] == '.' )
148 						continue;
149 					snprintf( p, MAX_PATH, "%s/%s", name, de->d_name );
150 					if ( !stat( p, &sb ) && S_ISREG( sb.st_mode )) {
151 						DEBUG(('Q',6,"add file '%s'",p));
152 						total += sb.st_size;
153 					}
154 				}
155 				closedir( d );
156 			} else
157 				write_log("can't open %s: %s",name,strerror(errno));
158 
159 			*size = total;
160 		}
161 	} else {
162 		DEBUG(('Q',4,"box '%s' lost",name));
163 		*mtime = 0;
164 		*size = 0;
165 	}
166 }
167 
168 
q_each(const char * fname,const ftnaddr_t * fa,int type,int flavor,int rslow)169 void q_each(const char *fname, const ftnaddr_t *fa, int type, int flavor, int rslow)
170 {
171 	qitem_t		*q;
172 	struct stat	sb;
173 	char		*callflavs = cfgs( CFG_CALLONFLAVORS );
174 	int		f = ( 1 << (flavor - 1)), canpoll = 0;
175 	int		cflav = 0;
176 
177 	DEBUG(('Q',4,"q_each: lo '%s'",fname));
178 
179 	cflav = (f & Q_CANPOLL) ? (strchr( callflavs, tolower( Q_CHARS[flavor - 1] ))
180 		|| strchr( callflavs, toupper( Q_CHARS[flavor - 1] ))) : 0;
181 
182 	q = q_add( fa );
183 	q->touched = 1;
184 	q->what |= type;
185 
186 	switch( type ) {
187 	case T_REQ:
188 		if ( !stat( fname, &sb ))
189 			q->reqs = sb.st_size;
190 		break;
191 
192 	case T_NETMAIL:
193 		if ( !stat( fname, &sb )) {
194 			q->pkts = sb.st_size;
195 			canpoll = 1;
196 		}
197 		break;
198 
199 	case T_ARCMAIL:
200 		canpoll = !q_recountflo( fname, &q->sizes[flavor-1], &q->times[flavor-1], rslow );
201 		break;
202 	}
203 
204 	q->canpoll |= ( cflav && canpoll && (f & Q_CANPOLL));
205 	q->flv |= f;
206 	DEBUG(('Q',4,"q_each: canpoll %d, q->canpoll %d, q->flv 0x%X(0x%X)",canpoll,q->canpoll,q->flv,f));
207 }
208 
209 
q_sum(const qitem_t * q)210 off_t q_sum(const qitem_t *q)
211 {
212 	int i;
213 	off_t total = 0;
214 
215 	for( i = 0; i < 6; i++ )
216 		if ( q->times[i] )
217 			total += q->sizes[i];
218 	return total;
219 }
220 
221 
rescan_boxes(int rslow)222 void rescan_boxes(int rslow)
223 {
224 	faslist_t *i;
225 	qitem_t *q;
226 	DIR *d;
227 	struct dirent *de;
228 	FTNADDR_T(a);
229 	char *p,rev[40],flv;
230 	int len,n;
231 	DEBUG(('Q',3,"rescan_boxes"));
232 	for(i=cfgfasl(CFG_FILEBOX);i;i=i->next) {
233 		q=q_add(&i->addr);
234 		q_recountbox(i->str,&q->sizes[4],&q->times[4],rslow);
235 		if(q->sizes[4]!=0) {
236 			q->touched=1;
237 			q->flv|=Q_HOLD;
238 			q->what|=T_ARCMAIL;
239 		}
240 	}
241 	if(cfgs(CFG_LONGBOXPATH)) {
242 		if((d=opendir(ccs))!=0) {
243 			while((de=readdir(d))) {
244 				if ( de->d_name[0] == '.' )
245 					continue;
246 				n=sscanf(de->d_name,"%d.%d.%d.%d.%c",&a.z,&a.n,&a.f,&a.p,&flv);
247 				if(n)DEBUG(('Q',4,"found lbox '%s', parse: %d:%d/%d.%d (%c) rc=%d",de->d_name,a.z,a.n,a.f,a.p,n==5?flv:'*',n));
248 				if(n==4||n==5) {
249 					if(n==4)snprintf(rev,40,"%d.%d.%d.%d",a.z,a.n,a.f,a.p);
250 					    else snprintf(rev,40,"%d.%d.%d.%d.%c",a.z,a.n,a.f,a.p,flv);
251 					if(!strcmp(de->d_name,rev)) {
252 						len=strlen(cfgs(CFG_LONGBOXPATH))+2+strlen(de->d_name);
253 						p=xmalloc(len);
254 						snprintf(p,len,"%s/%s",ccs,de->d_name);
255 						q=q_add(&a);
256 						q_recountbox(p,&q->sizes[5],&q->times[5],rslow);
257 						if(q->sizes[5]!=0) {
258 							q->touched=1;
259 							q->what|=T_ARCMAIL;
260 							cfgs(CFG_DEFBOXFLV);
261 							if(n==4)flv=(ccs&&*ccs)?(*ccs):'h';
262 							switch(tolower(flv)) {
263 							    case 'h': q->flv|=Q_HOLD;break;
264 							    case 'n':
265 							    case 'f': q->flv|=Q_NORM;break;
266 							    case 'd': q->flv|=Q_DIR;break;
267 							    case 'c': q->flv|=Q_CRASH;break;
268 							    case 'i': q->flv|=Q_IMM;break;
269 							    default : write_log("unknown longbox flavour '%c' for dir %s",flv,de->d_name);
270 							}
271 						}
272 						xfree(p);
273 					} else DEBUG(('Q',1,"strange: find: '%s', calc: '%s'",de->d_name,rev));
274 				} else if(*de->d_name!='.')DEBUG(('Q',2,"bad longbox name %s",de->d_name));
275 			}
276 			closedir(d);
277 		} else write_log("can't open %s: %s",ccs,strerror(errno));
278 	}
279 }
280 
281 
q_rescan(qitem_t ** curr,int rslow)282 int q_rescan(qitem_t **curr, int rslow)
283 {
284     sts_t sts;
285     qitem_t *q, **p;
286     time_t rescan_time;
287 
288     DEBUG(('Q',2,"rescan queue (%d)",rslow));
289     rescan_time = time( NULL );
290 
291     for( q = q_queue; q; q = q->next ) {
292         q->flv &= Q_DIAL;
293         q->what = q->touched = q->canpoll = 0;
294     }
295 
296     if ( outbound_rescan( q_each, rslow ) == 0 )
297         return 0;
298 
299     rescan_boxes( rslow );
300     p = &q_queue;
301     qqreset();
302     while(( q = *p )) {
303         if ( !q->touched ) {
304             *p = q->next;
305             if ( q == *curr )
306                 *curr = *p;
307             xfree( q );
308         } else {
309             outbound_getstatus( &q->addr, &sts );
310             q->flv |= sts.flags;
311             q->try = sts.try;
312             if ( sts.htime > time(NULL) )
313                 q->onhold = sts.htime;
314             else
315                 q->flv &= ~Q_ANYWAIT;
316 
317             qpqueue( &q->addr, q->pkts, q_sum( q ) + q->reqs, q->try, q->flv );
318             p = &( (*p)->next );
319         }
320     }
321 
322     if ( !*curr )
323         *curr = q_queue;
324 
325     rescan_time = time( NULL ) - rescan_time;
326 
327     DEBUG(('Q',2,"rescan done in %d seconds", rescan_time));
328     return 1;
329 }
330 
331 
qsendqueue(void)332 void qsendqueue(void)
333 {
334 	qitem_t *q;
335 
336 	qqreset();
337 
338 	for( q = q_queue; q ; q = q->next )
339 		qpqueue( &q->addr, q->pkts, q_sum( q ) + q->reqs, q->try, q->flv );
340 }
341