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