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