1 
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <sys/stat.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <dirent.h>
8 #include <sys/types.h>
9 #include <pthread.h>
10 #include <time.h>
11 #include <dlfcn.h>
12 #include <sys/time.h>
13 #include <time.h>
14 #include <syslog.h>
15 
16 #include "../pfqlib.h"
17 #include "pfqlib_priv.h"
18 #include "../config.h"
19 #include "../pfregex.h"
20 #include "../pfqmessage.h"
21 #include "../backends/pfq_backend.h"
22 
23 #define LOGLEVEL LOG_USER | LOG_ERR
24 
25 #define PFQ_SONAME "0.0.0"
26 
27 int dig_suspend;
28 
29 #define TH_UNINITIALIZED -1
30 #define TH_RUNNABLE       0
31 #define TH_STOPRQ         1
32 #define TH_STOPPED        2
33 int thread_control;
34 
35 int tmp_sort_sense;
36 
37 // Compare callbacks for qsort
msg_compare_from(const void * m1,const void * m2)38 int msg_compare_from ( const void *m1, const void *m2 ) {
39 	return tmp_sort_sense * strcmp ( ((struct msg_t*)m1)->from, ((struct msg_t*)m2)->from );
40 }
41 
msg_compare_to(const void * m1,const void * m2)42 int msg_compare_to ( const void *m1, const void *m2 ) {
43 	return tmp_sort_sense * strcmp ( ((struct msg_t*)m1)->to, ((struct msg_t*)m2)->to );
44 }
45 
msg_compare_subject(const void * m1,const void * m2)46 int msg_compare_subject ( const void *m1, const void *m2 ) {
47 	return tmp_sort_sense * strcmp ( ((struct msg_t*)m1)->subj, ((struct msg_t*)m2)->subj );
48 }
49 
pfql_getstatus(struct pfql_context_t * ctx)50 struct pfql_status_t* pfql_getstatus( struct pfql_context_t *ctx ) {
51 	return &ctx->pfql_status;
52 }
53 
pfql_getconf(struct pfql_context_t * ctx)54 struct pfql_conf_t* pfql_getconf( struct pfql_context_t *ctx) {
55 	return &ctx->pfql_conf;
56 }
57 
pfql_version()58 const char* pfql_version() {
59 	return PFQL_VERSION;
60 }
61 
pfql_queue_name(struct pfql_context_t * ctx,int i)62 const char* pfql_queue_name( struct pfql_context_t *ctx, int i) {
63 	return ctx->pfqbe_queue_name(i);
64 }
65 
pfql_queue_sort(struct pfql_context_t * ctx)66 void pfql_queue_sort ( struct pfql_context_t *ctx ) {
67 	tmp_sort_sense = ctx->pfql_status.sort_sense;
68 	if ( ctx->pfql_status.sort_field==PFQL_SORT_FROM )
69 		qsort ( ctx->queue, ctx->NUMMSG, sizeof(struct msg_t), msg_compare_from );
70 	if ( ctx->pfql_status.sort_field==PFQL_SORT_TO )
71 		qsort ( ctx->queue, ctx->NUMMSG, sizeof(struct msg_t), msg_compare_to );
72 	if ( ctx->pfql_status.sort_field==PFQL_SORT_SUBJECT )
73 		qsort ( ctx->queue, ctx->NUMMSG, sizeof(struct msg_t), msg_compare_subject );
74 }
75 
pfql_queue_last_changed(struct pfql_context_t * ctx)76 time_t pfql_queue_last_changed( struct pfql_context_t *ctx ) {
77 	return ctx->queue_last_changed;
78 }
79 
pfql_backend_apiversion(struct pfql_context_t * ctx)80 int pfql_backend_apiversion( struct pfql_context_t *ctx ) {
81 	return ctx->pfqbe_apiversion();
82 }
83 
pfql_backend_id(struct pfql_context_t * ctx)84 const char* pfql_backend_id( struct pfql_context_t *ctx ) {
85 	return ctx->pfqbe_id();
86 }
87 
pfql_backend_version(struct pfql_context_t * ctx)88 const char* pfql_backend_version( struct pfql_context_t *ctx ) {
89 	return ctx->pfqbe_version();
90 }
91 
pfql_retr_status(struct pfql_context_t * ctx,const char * id)92 int pfql_retr_status( struct pfql_context_t *ctx, const char *id ) {
93 	return ctx->pfqbe_retr_status(id);
94 }
95 
pfql_retr_headers(struct pfql_context_t * ctx,const char * id)96 int pfql_retr_headers( struct pfql_context_t *ctx, const char *id ) {
97 	return ctx->pfqbe_retr_headers(id);
98 }
99 
pfql_retr_body(struct pfql_context_t * ctx,const char * id,void * buf,size_t t)100 int pfql_retr_body( struct pfql_context_t *ctx, const char *id, void* buf, size_t t) {
101 int res;
102 	res = ctx->pfqbe_retr_body(id,buf,t);
103 	if ( res != PFBE_MSGNOTEX )
104 		return res;
105 	else
106 		return PFQL_MSGNOTEX;
107 }
108 
pfql_msg_getpos(struct pfql_context_t * ctx,const char * id)109 int pfql_msg_getpos( struct pfql_context_t *ctx, const char* id) {
110 int i;
111 	if ( !ctx->NUMMSG )
112 		return PFQL_MSGNOTEX;
113 	for ( i=0; i<ctx->NUMMSG; i++ ) {
114 		if ( !strcmp(id, ctx->queue[i].id ) )
115 			return i;
116 	}
117 	return PFQL_MSGNOTEX;
118 }
119 
pfql_num_msg(struct pfql_context_t * ctx)120 int pfql_num_msg( struct pfql_context_t *ctx ) {
121 	return ctx->NUMMSG;
122 }
123 
pfql_num_tag(struct pfql_context_t * ctx)124 int pfql_num_tag( struct pfql_context_t *ctx ) {
125 	return ctx->NUMTAG;
126 }
127 
pfql_msg_tag(struct pfql_context_t * ctx,const char * id)128 void pfql_msg_tag( struct pfql_context_t *ctx, const char* id) {
129 int i;
130 
131 	i = pfql_msg_getpos(ctx,id);
132 	if ( i==-1 )
133 		return;
134 
135 	if ( !ctx->queue[i].tagged ) {
136 		ctx->queue[i].tagged = 1;
137 		ctx->NUMTAG++;
138 	}
139 }
140 
pfql_msg_untag(struct pfql_context_t * ctx,const char * id)141 void pfql_msg_untag( struct pfql_context_t *ctx, const char* id) {
142 int i;
143 	i = pfql_msg_getpos(ctx,id);
144 	if ( i==-1 )
145 		return;
146 
147 	if ( ctx->queue[i].tagged ) {
148 		ctx->queue[i].tagged = 0;
149 		ctx->NUMTAG--;
150 	}
151 }
152 
pfql_msg_toggletag(struct pfql_context_t * ctx,const char * id)153 void pfql_msg_toggletag( struct pfql_context_t *ctx, const char* id) {
154 int i;
155 	i = pfql_msg_getpos(ctx,id);
156 	if ( i==-1 )
157 		return;
158 
159 	if ( ctx->queue[i].tagged )
160 		pfql_msg_untag(ctx,id);
161 	else
162 		pfql_msg_tag(ctx,id);
163 
164 }
165 
pfql_msg_istagged(struct pfql_context_t * ctx,const char * id)166 int pfql_msg_istagged( struct pfql_context_t *ctx, const char* id) {
167 int i;
168 	i = pfql_msg_getpos(ctx, id);
169 	if ( i==-1 )
170 		return 0;
171 	return ctx->queue[i].tagged;
172 }
173 
pfql_msg_at(struct pfql_context_t * ctx,int i)174 struct msg_t *pfql_msg_at( struct pfql_context_t *ctx, int i) {
175 	if ( i<ctx->NUMMSG )
176 		return &ctx->queue[i];
177 	else
178 		return NULL;
179 }
180 
pfql_msg(struct pfql_context_t * ctx,const char * id)181 struct msg_t *pfql_msg( struct pfql_context_t *ctx, const char* id) {
182 int i;
183 	i = pfql_msg_getpos(ctx, id);
184 	if ( i==-1 )
185 		return NULL;
186 	else
187 		return &ctx->queue[i];
188 }
189 
190 // Threaded loop
queue_fill_thread(void * arg)191 void* queue_fill_thread(void *arg) {
192 	int NUMMSG_NEW;
193 	int i;
194 	int b;
195 
196 	struct pfql_context_t *ctx = (struct pfql_context_t*)arg;
197 
198 	while ( thread_control == TH_RUNNABLE ) {
199 
200 		ctx->pfql_status.queue_status = PFQL_Q_FILLING;
201 
202 		if ( !dig_suspend && ctx->pfql_status.do_scan ) {
203 			if ( dig_limit )
204 				dig_start = time(NULL);
205 			NUMMSG_NEW = ctx->pfqbe_fill_queue();
206 			b = 0;
207 			if ( NUMMSG_NEW != ctx->NUMMSG )
208 				b = 1;
209 			ctx->NUMMSG = NUMMSG_NEW;
210 			for ( i=0; i<NUMMSG_NEW; i++ ) {
211 				if ( ctx->queue_thread[i].changed ) {
212 					memcpy ( ctx->queue[i].id, ctx->queue_thread[i].id, sizeof(ctx->queue[i].id) );
213 					memcpy ( ctx->queue[i].path, ctx->queue_thread[i].path, sizeof(ctx->queue[i].path) );
214 					ctx->queue[i].hcached = 0;
215 					ctx->queue[i].scached = 0;
216 					ctx->queue[i].tagged  = 0;
217 					b = 1;
218 
219 					if ( ctx->pfql_status.sort_field )
220 						pfql_retr_headers ( ctx, ctx->queue[i].id );
221 				}
222 			}
223 			if ( b )
224 				ctx->queue_last_changed = time(NULL);
225 			ctx->dig_lastqueue = ctx->pfql_status.cur_queue;
226 		}
227 		if ( ctx->pfql_status.sort_field!=PFQL_SORT_UNSORTED ) {
228 			ctx->pfql_status.queue_status = PFQL_Q_SORTING;
229 			pfql_queue_sort ( ctx );
230 			ctx->pfql_status.queue_status = PFQL_Q_IDLE;
231 		}
232 
233 		sleep ( ctx->pfql_conf.scan_delay );
234 	}
235 	pthread_mutex_unlock ( &ctx->qfill_mutex );
236 	thread_control = TH_STOPPED;
237 	pthread_exit(NULL);
238 }
239 
240 // Launches the dig thread
queue_fill_start(struct pfql_context_t * ctx)241 int queue_fill_start(struct pfql_context_t* ctx) {
242 	if ( pthread_mutex_trylock(&ctx->qfill_mutex)!=0 )
243 		return PFQL_ERROR;
244 	thread_control = TH_RUNNABLE;
245 	pthread_create ( &ctx->qfill_thread, NULL, queue_fill_thread, ctx );
246 	return PFQL_OK;
247 }
248 
249 // Stops the dig thread
queue_fill_stop()250 int queue_fill_stop() {
251 	if ( thread_control != TH_UNINITIALIZED )
252 		thread_control = TH_STOPRQ;
253 	while ( thread_control != TH_STOPPED && thread_control != TH_UNINITIALIZED )
254 		usleep ( 200000 );
255 	return 0;
256 }
257 
258 // Performs an action on the message
msg_action_do(struct pfql_context_t * ctx,const char * id,int act)259 void msg_action_do ( struct pfql_context_t *ctx, const char* id, int act ) {
260 
261 	switch ( act ) {
262 	case MSG_DELETE:
263 		ctx->pfqbe_message_delete ( id );
264 		break;
265 	case MSG_HOLD:
266 		ctx->pfqbe_message_hold ( id );
267 		break;
268 	case MSG_RELEASE:
269 		ctx->pfqbe_message_release ( id );
270 		break;
271 	case MSG_REQUEUE:
272 		ctx->pfqbe_message_requeue ( id );
273 		break;
274 	default:
275 		return;
276 	}
277 }
278 
279 // Tags all messages
pfql_tag_all(struct pfql_context_t * ctx)280 void pfql_tag_all( struct pfql_context_t *ctx ) {
281 int i;
282 	for ( i=0; i<ctx->NUMMSG; i++ )
283 		ctx->queue[i].tagged = TRUE;
284 	ctx->NUMTAG = ctx->NUMMSG;
285 }
286 
287 // Resets tag flag on all messages
pfql_tag_none(struct pfql_context_t * ctx)288 void pfql_tag_none( struct pfql_context_t *ctx ) {
289 int i;
290 	for ( i=0; i<ctx->NUMMSG; i++ )
291 		ctx->queue[i].tagged = FALSE;
292 	ctx->pfql_status.wrk_tagged = FALSE;
293 	ctx->NUMTAG = 0;
294 }
295 
296 // Reset the cache flag of the messages
msg_cachereset(struct pfql_context_t * ctx)297 void msg_cachereset( struct pfql_context_t *ctx ) {
298 int i;
299 	for ( i=0; i<ctx->NUMMSG; i++ )
300 		ctx->queue[i].hcached = 0;
301 }
302 
303 // Wrapper
pfql_msg_action(struct pfql_context_t * ctx,const char * id,int act)304 void pfql_msg_action ( struct pfql_context_t *ctx, const char *id, int act ) {
305 int i;
306 
307 	if ( (ctx->pfql_status.wrk_tagged) || (ctx->pfql_status.auto_wrk_tagged && ctx->NUMTAG) ) {
308 		dig_suspend = 1;
309 		for ( i = 0; i<ctx->NUMMSG; i++ ) {
310 			if ( ctx->queue[i].tagged )
311 				msg_action_do ( ctx, ctx->queue[i].id, act );
312 		}
313 		pfql_tag_none(ctx);
314 		dig_suspend = 0;
315 	} else {
316 		i = pfql_msg_getpos(ctx,id);
317 		if ( i==-1 )
318 			return;
319 		msg_action_do ( ctx, ctx->queue[i].id, act );
320 	}
321 	return;
322 }
323 
324 // Clears the queue
queue_reset(struct pfql_context_t * ctx)325 void queue_reset( struct pfql_context_t *ctx ) {
326 	memset ( ctx->queue, 0, sizeof(struct msg_t)*ctx->pfql_conf.msg_max );
327 }
328 
pfql_num_queues(struct pfql_context_t * ctx)329 int pfql_num_queues( struct pfql_context_t *ctx ) {
330 	return ctx->pfqbe_queue_count();
331 }
332 
333 // Changes the current queue
pfql_set_queue(struct pfql_context_t * ctx,int q)334 int pfql_set_queue( struct pfql_context_t *ctx, int q ) {
335 
336 	if ( q >= ctx->pfqbe_queue_count() )
337 		return PFQL_ERROR;
338 
339 	ctx->pfql_status.cur_queue = q;
340 	ctx->NUMTAG = 0;
341 	ctx->pfql_status.wrk_tagged = FALSE;
342 	queue_reset(ctx);
343 	ctx->queue_last_changed = time(NULL);
344 
345 	ctx->pfqbe_set_queue ( q );
346 
347 	// Ensure that a scan is made before proceeding, loop 1/5 sec
348 	while ( ctx->dig_lastqueue != ctx->pfql_status.cur_queue ) { usleep ( 200000 ); };
349 
350 	return PFQL_OK;
351 }
352 
353 // Search for a message; returns -1 if not found
msg_match(struct pfql_context_t * ctx,int reset,int direction)354 int msg_match( struct pfql_context_t *ctx, int reset, int direction) {
355 int i, res;
356 static int pos;
357 
358 	if ( reset )
359 		pos = -1;
360 	if ( direction==0 )
361 		pos++;
362 	else
363 		pos--;
364 	if ( pos<0 )
365 		return -1;
366 
367 	res = 0;
368 
369 	if ( direction==0 ) {
370 		for ( i=pos; i<ctx->NUMMSG; i++ ) {
371 			ctx->pfqbe_retr_headers ( ctx->queue[i].id );
372 			if ( ( (ctx->search_mode & SM_FROM) && regexec(ctx->regexp,ctx->queue[i].from,res,NULL,0)==0 ) ||
373 			     ( (ctx->search_mode & SM_TO)   && regexec(ctx->regexp,ctx->queue[i].to  ,res,NULL,0)==0 ) ||
374 			     ( (ctx->search_mode & SM_SUBJ) && regexec(ctx->regexp,ctx->queue[i].subj,res,NULL,0)==0 ) ) {
375 				pos = i;
376 				return i;
377 			}
378 		}
379 	} else {
380 		for ( i=pos; i>=0; i-- ) {
381 			ctx->pfqbe_retr_headers ( ctx->queue[i].id );
382 			if ( ( (ctx->search_mode & SM_FROM) && regexec(ctx->regexp,ctx->queue[i].from,res,NULL,0)==0 ) ||
383 			     ( (ctx->search_mode & SM_TO)   && regexec(ctx->regexp,ctx->queue[i].to  ,res,NULL,0)==0 ) ||
384 			     ( (ctx->search_mode & SM_SUBJ) && regexec(ctx->regexp,ctx->queue[i].subj,res,NULL,0)==0 ) ) {
385 				pos = i;
386 				return i;
387 			}
388 		}
389 	}
390 	return -1;
391 }
392 
pfql_msg_search(struct pfql_context_t * ctx,const char * regexps)393 int pfql_msg_search( struct pfql_context_t *ctx, const char* regexps) {
394 int res;
395 	res = regcomp ( ctx->regexp, regexps, 0 );
396 	if ( !res )
397 		return msg_match(ctx,1,0);
398 	else
399 		return PFQL_INVREGEXP;
400 }
401 
pfql_msg_searchnext(struct pfql_context_t * ctx,const char * regexps)402 int pfql_msg_searchnext( struct pfql_context_t *ctx, const char* regexps) {
403 int res;
404 	res = regcomp ( ctx->regexp, regexps, 0 );
405 	if ( !res )
406 		return msg_match(ctx,0,0);
407 	else
408 		return PFQL_INVREGEXP;
409 }
410 
pfql_msg_searchprev(struct pfql_context_t * ctx,const char * regexps)411 int pfql_msg_searchprev( struct pfql_context_t *ctx, const char* regexps) {
412 int res;
413 	res = regcomp ( ctx->regexp, regexps, 0 );
414 	if ( !res )
415 		return msg_match(ctx,0,1);
416 	else
417 		return PFQL_INVREGEXP;
418 }
419 
pfql_msg_searchandtag(struct pfql_context_t * ctx,const char * regexps)420 void pfql_msg_searchandtag ( struct pfql_context_t *ctx, const char* regexps) {
421 int res;
422 
423 	res = regcomp ( ctx->regexp, regexps, 0 );
424 	if ( !res ) {
425 		res = msg_match(ctx,1,0);
426 		while ( res != -1 ) {
427 			ctx->queue[res].tagged = 1;
428 			ctx->NUMTAG++;
429 			res = pfql_msg_searchnext(ctx,regexps);
430 		}
431 	}
432 }
433 
434 // Toggle envelope usage for from/to
pfql_toggle_envelope(struct pfql_context_t * ctx)435 void pfql_toggle_envelope(struct pfql_context_t *ctx) {
436 	if ( !(ctx->pfqbe_get_caps() & BECAPS_MSG_ENVELOPE) )
437 		return;
438 
439 	ctx->pfql_status.use_envelope = !ctx->pfql_status.use_envelope;
440 	msg_cachereset(ctx);
441 	ctx->pfqbe_use_envelope ( ctx->pfql_status.use_envelope );
442 }
443 
be_load(struct pfql_context_t * ctx,const char * be)444 int be_load ( struct pfql_context_t *ctx, const char* be ) {
445 	char buf[BUF_SIZE];
446 
447 	if ( strlen(ctx->pfql_conf.backends_path) )
448 		sprintf ( buf, "%s/libpfq_%s.so.%s", ctx->pfql_conf.backends_path, be, PFQ_SONAME );
449 	else
450 		sprintf ( buf, "%s/libpfq_%s.so.%s", PFBEDIR, be, PFQ_SONAME );
451 
452 	ctx->beptr = dlopen ( buf, RTLD_LAZY );
453 	if ( !ctx->beptr ) {
454 		syslog ( LOGLEVEL, "%s", dlerror() );
455 
456 		// Try 'pfqueue' subdir
457 		if ( strlen(ctx->pfql_conf.backends_path) )
458 			sprintf ( buf, "%s/pfqueue/libpfq_%s.so", ctx->pfql_conf.backends_path, be );
459 		else
460 			sprintf ( buf, "pfqueue/libpfq_%s.so", be );
461 		ctx->beptr = dlopen ( buf, RTLD_LAZY );
462 	}
463 	if ( !ctx->beptr ) {
464 		syslog ( LOGLEVEL, "%s", dlerror() );
465 		return PFQL_BENOTFOUND;
466 	}
467 
468 	ctx->pfqbe_apiversion = dlsym( ctx->beptr, "pfb_apiversion" );
469 	if ( !ctx->pfqbe_apiversion )
470 		return PFQL_BEMISSINGSYM;
471 
472 	if ( ctx->pfqbe_apiversion()!=3 )
473 		return PFQL_BEWRONGAPI;
474 
475 	ctx->pfqbe_init  = dlsym( ctx->beptr, "pfb_init" );
476 	if ( !ctx->pfqbe_init )
477 		return PFQL_BEMISSINGSYM;
478 
479 	ctx->pfqbe_close  = dlsym( ctx->beptr, "pfb_close" );
480 	if ( !ctx->pfqbe_close )
481 		return PFQL_BEMISSINGSYM;
482 
483 	ctx->pfqbe_id  = dlsym( ctx->beptr, "pfb_id" );
484 	if ( !ctx->pfqbe_id )
485 		return PFQL_BEMISSINGSYM;
486 
487 	ctx->pfqbe_version  = dlsym( ctx->beptr, "pfb_version" );
488 	if ( !ctx->pfqbe_version )
489 		return PFQL_BEMISSINGSYM;
490 
491 	ctx->pfqbe_setup = dlsym( ctx->beptr, "pfb_setup" );
492 	if ( !ctx->pfqbe_setup )
493 		return PFQL_BEMISSINGSYM;
494 
495 	ctx->pfqbe_fill_queue = dlsym( ctx->beptr, "pfb_fill_queue" );
496 	if ( !ctx->pfqbe_fill_queue )
497 		return PFQL_BEMISSINGSYM;
498 
499 	ctx->pfqbe_retr_headers = dlsym( ctx->beptr, "pfb_retr_headers" );
500 	if ( !ctx->pfqbe_retr_headers )
501 		return PFQL_BEMISSINGSYM;
502 
503 	ctx->pfqbe_retr_status = dlsym( ctx->beptr, "pfb_retr_status" );
504 	if ( !ctx->pfqbe_retr_status )
505 		return PFQL_BEMISSINGSYM;
506 
507 	ctx->pfqbe_retr_body = dlsym( ctx->beptr, "pfb_retr_body" );
508 	if ( !ctx->pfqbe_retr_body )
509 		return PFQL_BEMISSINGSYM;
510 
511 	ctx->pfqbe_message_delete = dlsym( ctx->beptr, "pfb_message_delete" );
512 	if ( !ctx->pfqbe_message_delete )
513 		return PFQL_BEMISSINGSYM;
514 
515 	ctx->pfqbe_message_hold = dlsym( ctx->beptr, "pfb_message_hold" );
516 	if ( !ctx->pfqbe_message_hold )
517 		return PFQL_BEMISSINGSYM;
518 
519 	ctx->pfqbe_message_release = dlsym( ctx->beptr, "pfb_message_release" );
520 	if ( !ctx->pfqbe_message_release )
521 		return PFQL_BEMISSINGSYM;
522 
523 	ctx->pfqbe_message_requeue = dlsym( ctx->beptr, "pfb_message_requeue" );
524 	if ( !ctx->pfqbe_message_requeue )
525 		return PFQL_BEMISSINGSYM;
526 
527 	ctx->pfqbe_set_queue = dlsym( ctx->beptr, "pfb_set_queue" );
528 	if ( !ctx->pfqbe_set_queue )
529 		return PFQL_BEMISSINGSYM;
530 
531 	ctx->pfqbe_use_envelope = dlsym( ctx->beptr, "pfb_use_envelope" );
532 	if ( !ctx->pfqbe_use_envelope )
533 		return PFQL_BEMISSINGSYM;
534 
535 	ctx->pfqbe_get_caps = dlsym( ctx->beptr, "pfb_get_caps" );
536 	if ( !ctx->pfqbe_get_caps )
537 		return PFQL_BEMISSINGSYM;
538 
539 	ctx->pfqbe_queue_name = dlsym( ctx->beptr, "pfb_queue_name" );
540 	if ( !ctx->pfqbe_queue_name )
541 		return PFQL_BEMISSINGSYM;
542 
543 	ctx->pfqbe_queue_count = dlsym( ctx->beptr, "pfb_queue_count" );
544 	if ( !ctx->pfqbe_queue_count )
545 		return PFQL_BEMISSINGSYM;
546 
547 	ctx->pfqbe_getconf = dlsym( ctx->beptr, "pfb_getconf" );
548 	if ( !ctx->pfqbe_queue_count )
549 		return PFQL_BEMISSINGSYM;
550 
551 	return PFQL_OK;
552 }
553 
be_try(struct pfql_context_t * ctx,const char * b)554 int be_try ( struct pfql_context_t *ctx, const char *b ) {
555 	int res;
556 
557 	res = be_load ( ctx, b );
558 	if ( res )
559 		return PFQL_ERROR;
560 
561 	res = ctx->pfqbe_init ();
562 	if ( res )
563 		return PFQL_ERROR;
564 
565 	ctx->pfqbe_getconf()->msg_max = ctx->pfql_conf.msg_max;
566 	ctx->pfqbe_getconf()->scan_limit = ctx->pfql_conf.scan_limit;
567 	res = ctx->pfqbe_setup(ctx->queue, ctx->queue_thread);
568 	if ( res )
569 		return PFQL_ERROR;
570 
571 	ctx->pfqbe_close(ctx);
572 
573 	return PFQL_OK;
574 }
575 
pfql_context_create(struct pfql_context_t ** ctx)576 int pfql_context_create ( struct pfql_context_t **ctx ) {
577 	*ctx = malloc(sizeof(struct pfql_context_t));
578 	if ( !ctx )
579 		return PFQL_MALLOC;
580 	else
581 		return PFQL_OK;
582 }
583 
pfql_init(struct pfql_context_t * ctx)584 int pfql_init(struct pfql_context_t *ctx) {
585 	/* Defaults */
586 	ctx->pfql_conf.max_char      = 200;
587 	ctx->pfql_conf.initial_queue = 0;
588 	sprintf ( ctx->pfql_conf.backends_path, "%c", 0 );
589 	sprintf ( ctx->pfql_conf.backend_name, "autodetect" );
590 	ctx->pfql_conf.msg_max       = 200;
591 	ctx->pfql_conf.scan_limit    = 0;
592 	ctx->pfql_conf.scan_delay    = 1;
593 	sprintf ( ctx->pfql_conf.remote_host, "%c", 0 );
594 	ctx->pfql_conf.remote_port   = 20000;
595 
596 	ctx->pfql_status.wrk_tagged      = 0;
597 	ctx->pfql_status.auto_wrk_tagged = 0;
598 	ctx->pfql_status.ask_confirm     = 1;
599 	ctx->pfql_status.do_scan         = 1;
600 	ctx->pfql_status.use_envelope    = 0;
601 	ctx->pfql_status.use_colors      = 1;
602 	ctx->pfql_status.cur_queue       = 0;
603 	ctx->pfql_status.sort_field      = PFQL_SORT_UNSORTED;
604 	ctx->pfql_status.sort_sense	 = PFQL_SORT_ASC;
605 
606 	ctx->beptr = 0;
607 	ctx->queue = 0;
608 	ctx->queue_thread = 0;
609 	ctx->regexp = 0;
610 
611 	ctx->NUMTAG = 0;
612 
613 	return PFQL_OK;
614 }
615 
pfql_backend_setconfig(struct pfql_context_t * ctx,const char * c)616 void pfql_backend_setconfig(struct pfql_context_t *ctx, const char* c) {
617 	strcpy ( ctx->pfqbe_getconf()->config_path, c );
618 }
619 
pfql_backend_setcommand(struct pfql_context_t * ctx,const char * c)620 void pfql_backend_setcommand(struct pfql_context_t *ctx, const char* c) {
621 	strcpy ( ctx->pfqbe_getconf()->command_path, c );
622 }
623 
pfql_start(struct pfql_context_t * ctx)624 int pfql_start(struct pfql_context_t *ctx) {
625 	int res;
626 
627 	thread_control = TH_UNINITIALIZED;
628 
629 	/* Alloc resources */
630 	ctx->regexp = (regex_t*) malloc (sizeof(regex_t));
631 	if ( !ctx->regexp ) {
632 		syslog ( LOGLEVEL, "pfqlib: sorry, cannot malloc for %d for the regex!", sizeof(regex_t) );
633 		return PFQL_MALLOC;
634 	}
635 	res = regcomp ( ctx->regexp, "*", 0 );
636 
637 	ctx->queue = (struct msg_t*)malloc(sizeof(struct msg_t)*ctx->pfql_conf.msg_max);
638 	if ( !ctx->queue ) {
639 		regfree ( ctx->regexp );
640 		syslog ( LOGLEVEL, "pfqlib: sorry, cannot malloc for %d elements (queue)!", ctx->pfql_conf.msg_max );
641 		return PFQL_MALLOC;
642 	}
643 
644 	ctx->beptr = 0;
645 
646 	ctx->queue_thread = (struct be_msg_t*)malloc(sizeof(struct be_msg_t)*ctx->pfql_conf.msg_max);
647 	if ( !ctx->queue_thread ) {
648 		regfree ( ctx->regexp );
649 		free ( ctx->queue );
650 		syslog ( LOGLEVEL, "pfqlib: sorry, cannot malloc for %d elements (queue_thread)!", ctx->pfql_conf.msg_max );
651 		return PFQL_MALLOC;
652 	}
653 
654 	if ( !strcmp ( ctx->pfql_conf.backend_name, "autodetect" ) ) {
655 		// Try to autodetect backend
656 		strcpy ( ctx->pfql_conf.backend_name, "exim" );
657 		res = be_try ( ctx, ctx->pfql_conf.backend_name );
658 		if ( res!=PFQL_OK ) {
659 			strcpy ( ctx->pfql_conf.backend_name, "postfix2" );
660 			res = be_try ( ctx, ctx->pfql_conf.backend_name );
661 		}
662 		if ( res!=PFQL_OK ) {
663 			strcpy ( ctx->pfql_conf.backend_name, "postfix1" );
664 			res = be_try ( ctx, ctx->pfql_conf.backend_name );
665 		}
666 		if ( res!=PFQL_OK ) {
667 			syslog ( LOGLEVEL, "pfqlib: cannot autodetect suitable backend, try -b and/or -B option" );
668 			ctx->beptr = 0;
669 			return PFQL_NOBE;
670 		}
671 	}
672 
673 	switch ( be_load ( ctx, ctx->pfql_conf.backend_name ) ) {
674 	case PFQL_BENOTFOUND:
675 		syslog ( LOGLEVEL, "pfqlib: backend not found!" );
676 		ctx->beptr = 0;
677 		return PFQL_BENOTFOUND;
678 	case PFQL_BEMISSINGSYM:
679 		syslog ( LOGLEVEL, "pfqlib: backend not valid (missing symbols)!" );
680 		ctx->beptr = 0;
681 		return PFQL_BEMISSINGSYM;
682 	}
683 
684 	strcpy ( ctx->pfqbe_getconf()->host, ctx->pfql_conf.remote_host );
685 	ctx->pfqbe_getconf()->port = ctx->pfql_conf.remote_port;
686 
687 	if ( ctx->pfqbe_init()!=PFBE_OK ) {
688 		syslog ( LOGLEVEL, "pfqlib: %s backend failed to init!", ctx->pfql_conf.backend_name );
689 		ctx->beptr = 0;
690 		return PFQL_BEINIT;
691 	}
692 
693 	strcpy ( ctx->pfqbe_getconf()->config_path, ctx->pfql_conf.backend_config );
694 	strcpy ( ctx->pfqbe_getconf()->command_path,ctx->pfql_conf.backend_progs );
695 	ctx->pfqbe_getconf()->msg_max = ctx->pfql_conf.msg_max;
696 	ctx->pfqbe_getconf()->scan_limit = ctx->pfql_conf.scan_limit;
697 
698 	if ( ctx->pfqbe_setup( ctx->queue, ctx->queue_thread )!=PFBE_OK ) {
699 		syslog ( LOGLEVEL, "pfqlib: %s backend failed to setup!", ctx->pfql_conf.backend_name );
700 		ctx->beptr = 0;
701 		return PFQL_BEINIT;
702 	}
703 
704 	ctx->dig_lastqueue = -1;
705 
706 	queue_fill_start( ctx );
707 	pfql_set_queue ( ctx, ctx->pfql_conf.initial_queue );
708 
709 	return PFQL_OK;
710 
711 }
712 
pfql_context_destroy(struct pfql_context_t * ctx)713 int pfql_context_destroy(struct pfql_context_t *ctx) {
714 
715 	pthread_mutex_destroy ( &ctx->qfill_mutex );
716 	queue_fill_stop(ctx);
717 
718 	if (ctx->beptr) {
719 		ctx->pfqbe_close(ctx);
720 		dlclose (ctx->beptr);
721 	}
722 
723 	if ( ctx->queue )
724 		free ( ctx->queue );
725 	if ( ctx->queue_thread )
726 		free ( ctx->queue_thread );
727 	if ( ctx->regexp )
728 		regfree ( ctx->regexp );
729 
730 	return PFQL_OK;
731 
732 }
733 
pfql_dump(struct pfql_context_t * ctx,const char * fname)734 int pfql_dump ( struct pfql_context_t *ctx, const char *fname ) {
735 	return PFQL_OK;
736 }
737