1
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <unistd.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 #include <time.h>
9
10 #include "fe_ncurses.h"
11 #include "ncgui.h"
12 #include "config.h"
13 #include "pfqhelp.h"
14 #include "pfqmessage.h"
15 #include "pfregex.h"
16 #include "pfqconfig.h"
17 #include "pfqlib.h"
18
19 #define CAT_BUF_SIZE 20*1024
20 #define BUF_SIZE 250
21
22 char *a_names[]={
23 "hold",
24 "delete",
25 "release",
26 "requeue"
27 };
28
29 char *s_names[]={
30 "unsorted",
31 "sorted by from",
32 "sorted by to",
33 "sorted by subject"
34 };
35
36 int page_step;
37 int MSGMARK;
38
39 char* cat_buf;
40 char* regexps;
41
42 struct pfql_context_t *pfql_ctx;
43
44 struct msg_list_t *msg_list; /* Array of CURRENTLY SHOWN msg ids */
45 int msg_num; /* Number of messages in the queue */
46
47 time_t last_repaint;
48
49 int half_delay_time;
50 int show_body_win;
51 int show_body_always;
52 int show_body_fromline;
53
wnd_confirm(const char * action)54 int wnd_confirm ( const char *action ) {
55 int c, ret;
56
57 WINDOW *w = newwin ( 5, 50, (LINES-5)/2, (COLS-50)/2 );
58 wnd_border ( w );
59
60 if ( pfql_getstatus(pfql_ctx)->use_colors )
61 wbkgd ( w, COLOR_PAIR(CP_DIALOG) );
62
63 nocbreak();
64 cbreak();
65
66 if ( pfql_getstatus(pfql_ctx)->wrk_tagged || (pfql_getstatus(pfql_ctx)->auto_wrk_tagged && pfql_num_tag(pfql_ctx)) )
67 mvwprintw ( w, 2, 2, "Do you really want to %s tagged messages?", action );
68 else
69 mvwprintw ( w, 2, 2, "Do you really want to %s this message?", action );
70 wrefresh ( w );
71
72 c = wgetch ( w );
73 ret = ( c=='y' || c=='Y' ? 1 : 0 );
74
75 delwin ( w );
76
77 halfdelay ( half_delay_time*10 );
78 return ret;
79 }
80
wnd_change_sort_field()81 int wnd_change_sort_field () {
82 int c, ret;
83
84 WINDOW *w = newwin ( 8, 50, (LINES-8)/2, (COLS-50)/2 );
85 wnd_border ( w );
86
87 if ( pfql_getstatus(pfql_ctx)->use_colors )
88 wbkgd ( w, COLOR_PAIR(CP_DIALOG) );
89
90 nocbreak();
91 cbreak();
92
93 mvwprintw ( w, 1, 2, "Choose sort field:" );
94 mvwprintw ( w, 3, 2, "0: unsorted" );
95 mvwprintw ( w, 4, 2, "1: from (4 descendent)" );
96 mvwprintw ( w, 5, 2, "2: to (5 descendent)" );
97 mvwprintw ( w, 6, 2, "3: subject (6 descendent)" );
98
99 wrefresh ( w );
100
101 c = wgetch ( w );
102
103 if ( c>='0' && c<='6' )
104 ret = c-'0';
105 else
106 ret = -1;
107
108 delwin ( w );
109
110 halfdelay ( half_delay_time*10 );
111 return ret;
112
113 }
114
wnd_getregexp()115 void wnd_getregexp () {
116 char *tmp;
117
118 WINDOW *w = newwin ( 5, 60, (LINES-5)/2, (COLS-60)/2 );
119 if ( pfql_getstatus(pfql_ctx)->use_colors )
120 wbkgd ( w, COLOR_PAIR(CP_DIALOG) );
121 wnd_border ( w );
122
123 echo();
124 nocbreak();
125 cbreak();
126
127 mvwaddstr ( w, 1, 2, "Insert POSIX regular expression to search for:" );
128 wrefresh ( w );
129
130 wnd_prompt ( w, 3, 2, regexps, REGEXP_LEN );
131
132 delwin ( w );
133 halfdelay ( half_delay_time*10 );
134 noecho();
135
136 pfql_ctx->search_mode = SM_ALL;
137 if ( !strncmp( regexps, "f:", 2 ) )
138 pfql_ctx->search_mode = SM_FROM;
139 if ( !strncmp( regexps, "t:", 2 ) )
140 pfql_ctx->search_mode = SM_TO;
141 if ( !strncmp( regexps, "e:", 2 ) )
142 pfql_ctx->search_mode = SM_TO | SM_FROM;
143 if ( !strncmp( regexps, "s:", 2 ) )
144 pfql_ctx->search_mode = SM_SUBJ;
145
146 if ( pfql_ctx->search_mode != ( SM_ALL ) ) {
147 tmp = (char*) malloc ( REGEXP_LEN );
148 strncpy ( tmp, regexps+2, REGEXP_LEN );
149 strncpy ( regexps, tmp, REGEXP_LEN );
150 free ( tmp );
151 }
152
153 return;
154 }
155
version()156 void version() {
157 printf ( "pfqueue - Version %s - (C) 2004-2007 Stefano Rivoir\n",
158 VERSION );
159 }
160
usage()161 void usage() {
162 version();
163 printf ( "Usage: pfqueue [-ehvn] [-b postfix1|postfix2|exim] [-q queue_num] [-m max_msg]\n"
164 " [-s autorefresh_seconds] [-l limit_seconds] -[B backends_path]\n"
165 " [-p executables_path] [-c config_path]\n" );
166 }
167
help()168 void help() {
169 WINDOW *w;
170 char *ht;
171 int c;
172 char *help_be;
173
174 help_be = (char*)(malloc ( 1024 ) );
175 sprintf ( help_be,
176 " pfqueue lib version: %s\n"
177 " Backend API version: %d\n\n"
178 " Backend ID: %s\n"
179 " Backend version: %s",
180 pfql_version(), pfql_backend_apiversion(pfql_ctx), pfql_backend_id(pfql_ctx), pfql_backend_version(pfql_ctx) );
181
182 w = newwin ( 25, 60, (LINES-26)/2,(COLS-60)/2 );
183 if ( pfql_getstatus(pfql_ctx)->use_colors )
184 wbkgd ( w, COLOR_PAIR(CP_DIALOG) );
185
186 nocbreak();
187 cbreak();
188
189 ht = help_text1;
190
191 c = 0;
192 while ( c!='q' && c!='Q' ) {
193 wclear ( w );
194 mvwprintw ( w, 1, 0, ht );
195 wnd_border ( w );
196 wattron ( w, A_BOLD );
197 mvwaddstr ( w, 0, 28, "Help" );
198 mvwaddstr ( w, 0, 2, "pfqueue ver. " );
199 mvwaddstr ( w, 0, 15, VERSION );
200 mvwaddstr ( w, 23, 2, "Press q to exit help, any key for next page" );
201 wattroff ( w, A_BOLD );
202 wrefresh ( w );
203 c = wgetch ( w );
204 if ( ht==help_text1 )
205 ht = help_text2;
206 else if ( ht == help_text2 )
207 ht = help_be;
208 else
209 ht = help_text1;
210 }
211 delwin ( w );
212
213 free ( help_be );
214 halfdelay ( half_delay_time*10 );
215 }
216
goto_msg(int i)217 int goto_msg(int i) {
218 int j;
219
220 if ( i<0 || i>=msg_num )
221 return 0;
222
223 PREVROW = CURROW;
224 PREVMSG = CURMSG;
225 CURMSG = i;
226 CURROW = (i-FIRSTMSG)+FIRSTROW;
227
228 show_body_fromline = 0;
229
230 if ( CURROW<FIRSTROW ) {
231 CURROW = FIRSTROW;
232 FIRSTMSG = CURMSG;
233 return 1;
234 }
235 if ( CURROW>MAXROW ) {
236 j = CURROW-MAXROW;
237 FIRSTMSG += j;
238 CURROW = MAXROW;
239 return 1;
240 }
241 return 0;
242 }
243
goto_next()244 int goto_next() {
245 return goto_msg( CURMSG+1 );
246 }
247
goto_prev()248 int goto_prev() {
249 return goto_msg( CURMSG-1 );
250 }
251
goto_first()252 int goto_first() {
253 return goto_msg(0);
254 }
255
goto_last()256 int goto_last() {
257 if ( msg_num )
258 return goto_msg( msg_num-1 );
259 return 0;
260 }
261
goto_nextpage()262 int goto_nextpage() {
263 if ( CURMSG+page_step < msg_num-1 )
264 return goto_msg ( CURMSG+page_step );
265 else
266 return goto_msg ( msg_num-1 );
267 }
268
goto_prevpage()269 int goto_prevpage() {
270 if ( CURMSG > page_step )
271 return goto_msg ( CURMSG-page_step );
272 else
273 return goto_msg ( 0 );
274 }
275
win_header()276 void win_header() {
277
278 wattron ( hwnd, A_BOLD );
279
280 if ( pfql_getstatus(pfql_ctx)->use_colors )
281 wattron ( hwnd, COLOR_PAIR(CP_HEAD) );
282
283 mvwprintw ( hwnd, 0, 1, "Queue: '%s', %d message%s, %d tagged, %s",
284 pfql_queue_name(pfql_ctx,pfql_getstatus(pfql_ctx)->cur_queue), msg_num,
285 ( msg_num != 1 ? "s" : "" ),
286 pfql_num_tag(pfql_ctx),
287 s_names[pfql_getstatus(pfql_ctx)->sort_field]);
288 wclrtoeol ( hwnd );
289
290 wattroff ( hwnd, A_REVERSE );
291 if ( pfql_getstatus(pfql_ctx)->auto_wrk_tagged )
292 wattron ( hwnd, A_REVERSE );
293 mvwaddstr ( hwnd, 0, COLS-7, "A" );
294
295 wattroff ( hwnd, A_REVERSE );
296 if ( pfql_getstatus(pfql_ctx)->wrk_tagged )
297 wattron ( hwnd, A_REVERSE );
298 mvwaddstr ( hwnd, 0, COLS-6, "T" );
299
300 wattroff ( hwnd, A_REVERSE );
301 if ( pfql_getstatus(pfql_ctx)->ask_confirm )
302 wattron ( hwnd, A_REVERSE );
303 mvwaddstr ( hwnd, 0, COLS-5, "C" );
304
305 wattroff ( hwnd, A_REVERSE );
306 if ( pfql_getstatus(pfql_ctx)->do_scan )
307 wattron ( hwnd, A_REVERSE );
308 mvwaddstr ( hwnd, 0, COLS-4, "S" );
309
310 wattroff ( hwnd, A_REVERSE );
311 if ( show_body_always )
312 wattron ( hwnd, A_REVERSE );
313 mvwaddstr ( hwnd, 0, COLS-3, "B" );
314
315 wattroff ( hwnd, A_REVERSE );
316 wattron ( hwnd, A_BOLD );
317 mvwaddstr ( hwnd, 1, 1, "ID" );
318 mvwaddstr ( hwnd, 1, COL1, "From" );
319 mvwaddstr ( hwnd, 1, COL2, "To" );
320 wattroff ( hwnd, A_BOLD );
321 wattroff ( hwnd, COLOR_PAIR(CP_HEAD) );
322 wnoutrefresh ( hwnd );
323 }
324
325 // Sizes the window according to the (new) screen size
win_resize()326 void win_resize () {
327 int mwnd_tot;
328 int bwnd_tot;
329 int lwnd_tot;
330
331 bwnd_tot = bwnd_height + 2;
332 if ( mwnd )
333 delwin ( mwnd );
334 if ( mwndb )
335 delwin ( mwndb );
336 if ( bwnd )
337 delwin ( bwnd );
338 if ( bwndb )
339 delwin ( bwndb );
340 if ( lwnd )
341 delwin ( lwnd );
342 if ( hwnd )
343 delwin ( hwnd );
344 if ( bline )
345 free ( bline );
346 if ( msg_list )
347 free ( msg_list );
348
349 last_repaint = 0;
350 mainwnd = initscr();
351 FIRSTROW = 0;
352
353 if ( !has_colors() || start_color()==ERR )
354 pfql_getstatus(pfql_ctx)->use_colors = 0;
355
356 bline = (char*)malloc(sizeof(char)*COLS+1);
357 memset ( bline, ' ', sizeof(char)*COLS+1 );
358 *(bline+COLS) = 0;
359 msg_list = (struct msg_list_t*)malloc(sizeof(struct msg_list_t)*(LINES));
360
361 mwnd_tot = 7;
362 lwnd_tot = LINES-mwnd_tot-2;
363 if ( show_body_win )
364 lwnd_tot -= bwnd_height;
365
366 MAXROW = LINES-(mwnd_tot)-1-2;
367 if ( show_body_win )
368 MAXROW -= bwnd_height;
369
370 hwnd = newwin ( 2, COLS, 0, 0 );
371 lwnd = newwin ( lwnd_tot, COLS, 2, 0 );
372 mwndb = newwin ( mwnd_tot, COLS, lwnd_tot+2, 0 );
373 mwnd = newwin ( mwnd_tot-2, COLS-2, lwnd_tot+3, 1 );
374 if ( show_body_win ) {
375 bwndb = newwin ( bwnd_height, COLS, lwnd_tot+2+mwnd_tot, 0 );
376 bwnd = newwin ( bwnd_height-2, COLS-2, lwnd_tot+2+mwnd_tot+1, 1 );
377 }
378
379 if ( pfql_getstatus(pfql_ctx)->use_colors ) {
380 init_pair ( CP_MSG, COLOR_WHITE, COLOR_MAGENTA );
381 init_pair ( CP_HEAD,COLOR_WHITE, COLOR_BLUE );
382 init_pair ( CP_TAG, COLOR_YELLOW, COLOR_BLACK );
383 init_pair ( CP_DIALOG, COLOR_WHITE, COLOR_RED );
384 init_pair ( CP_OPTDIS, COLOR_RED, COLOR_BLUE );
385 wbkgd ( mwndb, COLOR_PAIR(CP_HEAD) );
386 if ( show_body_win )
387 wbkgd ( bwndb, COLOR_PAIR(CP_HEAD) );
388 wbkgd ( hwnd, COLOR_PAIR(CP_HEAD) );
389 }
390
391 if ( pfql_getstatus(pfql_ctx)->use_envelope )
392 wnd_clear ( mwndb, "Message (from envelope)" );
393 else
394 wnd_clear ( mwndb, "Message (from headers)" );
395
396 if ( show_body_win )
397 wnd_clear ( bwndb, "Message body" );
398
399 COL1 = 20;
400 COL2 = COL1+( COLS - COL1 ) / 2-2;
401
402 noecho();
403 halfdelay(half_delay_time*10);
404
405 wnoutrefresh ( mwndb );
406 if ( show_body_win )
407 wnoutrefresh ( bwndb );
408
409 page_step = MAXROW ;
410
411 doupdate();
412 }
413
414 // Displays the bottom window
msg_show_headers()415 void msg_show_headers () {
416 struct msg_t *msg;
417
418 if ( !msg_num ) {
419 wclear ( mwnd );
420 mvwaddstr ( mwnd, 0, 0, "Queue is empty" );
421 return;
422 }
423
424 msg = pfql_msg( pfql_ctx, msg_list[CURROW].id );
425 if ( !msg )
426 return;
427
428 pfql_retr_status ( pfql_ctx, msg->id );
429 pfql_retr_headers( pfql_ctx, msg->id );
430
431 mvwaddstr ( mwnd, 0, 0, "Message:" );
432 wclrtobot ( mwnd );
433 mvwaddstr ( mwnd, 0, 9, msg->id );
434
435 mvwaddstr ( mwnd, 1, 0, "From..:" );
436 mvwaddstr ( mwnd, 1, 8, msg->from );
437
438 mvwaddstr ( mwnd, 2, 0, "To....:" );
439 mvwaddstr ( mwnd, 2, 8, msg->to );
440
441 mvwaddstr ( mwnd, 3, 0, "Subj..:" );
442 mvwaddstr ( mwnd, 3, 8, msg->subj );
443
444 mvwaddstr ( mwnd, 4, 0, "Status:" );
445 mvwaddstr ( mwnd, 5, 0, " " );
446 mvwaddstr ( mwnd, 4, 8, msg->stat );
447
448 if ( show_body_always && show_body_win )
449 msg_show_body(0);
450 }
451
452 // Returns the message displayed at row r
msg_at(int r)453 int msg_at(int r) {
454 return (FIRSTMSG+r-FIRSTROW);
455 }
456
457 // Clears the cursor in the previous position and displays the current one
show_cursor()458 void show_cursor() {
459 char *buf;
460 int i;
461 struct msg_t *msg;
462
463 buf = (char*)malloc(BUF_SIZE);
464
465 // Current row
466 i = msg_at(CURROW);
467 mvwinnstr ( lwnd, CURROW, 0, buf, COLS );
468
469 if ( pfql_getstatus(pfql_ctx)->use_colors )
470 wattron ( lwnd, COLOR_PAIR(CP_MSG) );
471 else
472 wattron ( lwnd, A_REVERSE );
473
474 msg = pfql_msg_at(pfql_ctx,i);
475 if ( msg && msg->tagged )
476 wattron ( lwnd, A_BOLD );
477
478 mvwaddstr ( lwnd, CURROW, 0, buf );
479 wattroff ( lwnd, COLOR_PAIR(CP_MSG) );
480 wattroff ( lwnd, A_BOLD );
481 wattroff ( lwnd, A_REVERSE );
482
483 // Previous row
484 if ( PREVROW!=CURROW ) {
485 i = msg_at(PREVROW);
486 mvwinnstr ( lwnd, PREVROW, 0, buf, COLS );
487 msg = pfql_msg_at(pfql_ctx,i);
488 if ( msg ) {
489 if ( msg->tagged )
490 wattron ( lwnd, A_BOLD );
491 if ( msg->tagged && pfql_getstatus(pfql_ctx)->use_colors )
492 wattron ( lwnd, COLOR_PAIR(CP_TAG) );
493 }
494 mvwaddstr ( lwnd, PREVROW, 0, buf );
495 }
496
497 free ( buf );
498 wattroff ( lwnd, COLOR_PAIR(CP_MSG) );
499 wattroff ( lwnd, COLOR_PAIR(CP_TAG) );
500 wattroff ( lwnd, A_BOLD );
501 wattroff ( lwnd, A_REVERSE );
502
503 wrefresh ( hwnd );
504
505 wmove ( lwnd, CURROW, 0 );
506
507 PREVROW = CURROW;
508
509 msg_show_headers();
510 wrefresh ( mwnd );
511 }
512
msg_cat_body(WINDOW * pw,WINDOW * bw,int wl,int wc,int ctrls)513 void msg_cat_body( WINDOW *pw, WINDOW* bw, int wl, int wc, int ctrls ) {
514 char lines[MSG_MAX_ROWS][MSG_MAX_COLS];
515 int j, i;
516 int c;
517 int fline;
518 int pgstep;
519 int msglines;
520 int ptr;
521 int buflen;
522 int maxcol;
523
524 maxcol = wc-2;
525 memset ( lines, 0, sizeof(lines) );
526
527 buflen = pfql_retr_body ( pfql_ctx, msg_list[CURROW].id, cat_buf, CAT_BUF_SIZE );
528 if ( buflen == PFQL_MSGNOTEX )
529 return;
530
531 msglines = 0;
532 ptr = 0;
533
534 // Copy cat_buf into splitted lines
535 while ( ptr<buflen && msglines < MSG_MAX_ROWS ) {
536 c = 0;
537 while ( c < maxcol && *(cat_buf+ptr)!='\n' ) {
538 lines[msglines][c] = *(cat_buf+ptr);
539 ptr++;
540 c++;
541 }
542 while ( *(cat_buf+ptr)!='\n' )
543 ptr++;
544 ptr++;
545 msglines++;
546 }
547
548 keypad ( pw, TRUE );
549 pgstep = wl;
550
551 if ( bw ) {
552 wattron ( bw, A_BOLD );
553 mvwaddstr ( bw, 0, 2, "Body of" );
554 mvwaddstr ( bw, 0, 10, pfql_msg_at(pfql_ctx,CURMSG)->path );
555 wattroff ( bw, A_BOLD );
556 wrefresh ( bw );
557 }
558
559 c = 0;
560 if ( ctrls )
561 fline = 0;
562 else
563 fline = show_body_fromline;
564
565 while ( c!='q' && c!='Q' ) {
566 j = fline;
567 i = 0;
568 while ( j<MSG_MAX_ROWS && i < wl ) {
569 mvwaddnstr ( pw, i++, 2, lines[j++], maxcol );
570 wclrtoeol ( pw );
571 }
572 wrefresh ( pw );
573
574 no_fill:
575 if ( ctrls )
576 c = wgetch (pw);
577 else
578 c = 'q';
579
580 switch (c) {
581 case 'g':
582 case KEY_HOME:
583 fline = 0;
584 break;
585 case 'G':
586 case KEY_END:
587 fline = msglines-pgstep;
588 break;
589 case KEY_PPAGE:
590 if ( fline > pgstep )
591 fline -= pgstep;
592 else
593 fline = 0;
594 break;
595 case KEY_NPAGE:
596 if ( fline < (msglines-pgstep) )
597 fline += pgstep;
598 break;
599 case KEY_UP:
600 if ( fline )
601 fline--;
602 break;
603 case ' ':
604 case KEY_DOWN:
605 if ( fline<msglines-pgstep )
606 fline++;
607 break;
608 case 'q':
609 case 'Q':
610 break;
611 default:
612 goto no_fill;
613 break;
614 }
615 }
616
617 halfdelay ( half_delay_time*10 );
618 }
619
msg_show_body(int force_own)620 void msg_show_body(int force_own) {
621 WINDOW *w1, *w2;
622 if ( show_body_win && !force_own )
623 msg_cat_body ( bwnd, bwndb, bwnd_height-2, COLS-2, 0 );
624 else {
625 w1 = newwin ( LINES-4, COLS-4, 2, 2 );
626 w2 = newwin ( LINES-6, COLS-6, 3, 3 );
627 wnd_border ( w1 );
628 wrefresh ( w1 );
629 msg_cat_body ( w2, w1, LINES-6, COLS-6, 1 );
630 delwin ( w2 );
631 delwin ( w1 );
632 }
633 }
634
635 // Returns 1 if queue needs repaint
queue_needs_repaint()636 int queue_needs_repaint () {
637 return ( pfql_queue_last_changed(pfql_ctx) >= last_repaint );
638 }
639
640 // Set repaint flag
queue_force_repaint(int f)641 void queue_force_repaint(int f) {
642 if ( f )
643 last_repaint = 0;
644 else
645 last_repaint = pfql_queue_last_changed(pfql_ctx);
646 }
647
648 // Displays the list of messages
queue_show()649 void queue_show() {
650 int i, j;
651 //time_t show_start;
652 struct msg_t *msg;
653
654 j = FIRSTROW;
655 i = FIRSTMSG;
656
657 msg_num = pfql_num_msg(pfql_ctx);
658
659 last_repaint = time(NULL);
660
661 if ( pfql_getstatus(pfql_ctx)->sort_field!=PFQL_SORT_UNSORTED )
662 while ( pfql_ctx->pfql_status.queue_status!=PFQL_Q_IDLE ) { usleep(5000); }
663
664 while ( j <= MAXROW ) {
665
666 if ( i<msg_num ) {
667
668 msg = pfql_msg_at(pfql_ctx,i);
669 if ( !msg )
670 return;
671 strcpy ( msg_list[j].id, msg->id );
672
673 pfql_retr_headers ( pfql_ctx,msg->id );
674
675 if ( msg->tagged ) {
676 wattron ( lwnd, A_BOLD );
677 if ( pfql_getstatus(pfql_ctx)->use_colors )
678 wattron ( lwnd, COLOR_PAIR(CP_TAG) );
679 }
680 mvwaddnstr ( lwnd, j, 0, bline, COLS );
681 mvwaddnstr ( lwnd, j, 1, msg->id, sizeof(msg->id) );
682 mvwaddnstr ( lwnd, j, COL1, msg->from, COL2-2-COL1 );
683 mvwaddstr ( lwnd, j, COL2-2, " " );
684 mvwaddnstr ( lwnd, j, COL2, msg->to, COLS-2-COL2 );
685 wattroff ( lwnd, A_BOLD );
686 wattroff ( lwnd, COLOR_PAIR(CP_TAG) );
687 } else {
688 mvwaddstr ( lwnd, j, 1, " " );
689 wclrtobot ( lwnd );
690 j = MAXROW+1; // Force loop exit
691 }
692 j++;
693 i++;
694 }
695
696 if ( msg_num && CURMSG > (msg_num-1) )
697 goto_last();
698 keypad ( lwnd, 1 );
699 win_header();
700 show_cursor();
701 wnoutrefresh ( mwnd );
702 wnoutrefresh ( lwnd );
703 doupdate();
704 wrefresh ( lwnd );
705 }
706
707 // Init frontend
fe_init()708 int fe_init() {
709 cat_buf = 0;
710 bwnd_height = 10;
711
712 cat_buf = (char*)malloc(CAT_BUF_SIZE);
713 if ( !cat_buf )
714 return 0;
715
716 regexps = 0;
717 regexps = (char*)malloc(REGEXP_LEN);
718 if ( !regexps )
719 return 0;
720
721 mainwnd = mwndb = lwnd = mwnd = hwnd = bwnd = bwndb = NULL;
722 bline = 0;
723 msg_list = 0;
724 return 1;
725 }
726
fe_close()727 void fe_close() {
728 if ( cat_buf )
729 free ( cat_buf );
730 if ( msg_list )
731 free ( msg_list );
732 if ( bline )
733 free ( bline );
734 if ( regexps )
735 free ( regexps );
736 }
737
queue_change(int q)738 void queue_change(int q) {
739 int r;
740
741 r = pfql_set_queue(pfql_ctx,q);
742 if ( r==PFQL_OK ) {
743 CURMSG = 0;
744 goto_first();
745 win_header();
746 }
747 }
748
msg_action(const char * id,int act)749 void msg_action(const char* id, int act) {
750 if ( !msg_num )
751 return;
752 if ( (pfql_getstatus(pfql_ctx)->ask_confirm && wnd_confirm(a_names[act])) ||
753 (!pfql_getstatus(pfql_ctx)->ask_confirm) )
754 pfql_msg_action(pfql_ctx, id, act);
755 queue_force_repaint(1);
756 }
757
main_loop()758 void main_loop() {
759 int c, r;
760 int i;
761
762 c = 0;
763 CURMSG = 0;
764 MSGMARK = -1;
765
766 FIRSTMSG = 0;
767
768 while ( c != 'q' && c != 'Q' ) {
769
770 if ( queue_needs_repaint() )
771 queue_show();
772 else
773 show_cursor();
774
775 c = wgetch ( lwnd );
776
777 switch ( c ) {
778 case 'G':
779 case KEY_END:
780 queue_force_repaint ( goto_last() );
781 break;
782 case 'g':
783 case KEY_HOME:
784 queue_force_repaint ( goto_first() );
785 break;
786 case KEY_UP:
787 queue_force_repaint ( goto_prev() );
788 break;
789 case KEY_DOWN:
790 queue_force_repaint ( goto_next() );
791 break;
792 case KEY_PPAGE:
793 queue_force_repaint ( goto_prevpage() );
794 break;
795 case KEY_NPAGE:
796 queue_force_repaint ( goto_nextpage() );
797 break;
798 case KEY_RESIZE:
799 win_resize();
800 break;
801 case 'e':
802 pfql_toggle_envelope(pfql_ctx);
803 queue_force_repaint ( 1 );
804 break;
805 case 'd':
806 case KEY_DC:
807 msg_action( msg_list[CURROW].id, MSG_DELETE );
808 break;
809 case 'h':
810 msg_action( msg_list[CURROW].id, MSG_HOLD );
811 break;
812 case 'l':
813 msg_action ( msg_list[CURROW].id, MSG_RELEASE );
814 break;
815 case 'r':
816 msg_action ( msg_list[CURROW].id, MSG_REQUEUE );
817 break;
818 case '1':
819 queue_change ( Q_DEFERRED );
820 break;
821 case '4':
822 queue_change ( Q_HOLD );
823 break;
824 case '3':
825 queue_change ( Q_INCOMING );
826 break;
827 case '2':
828 queue_change ( Q_ACTIVE );
829 break;
830 case '5':
831 queue_change ( Q_CORRUPT );
832 break;
833 case 'a':
834 pfql_tag_all(pfql_ctx);
835 queue_force_repaint ( 1 );
836 win_header();
837 break;
838 case 'm':
839 MSGMARK = CURMSG;
840 pfql_msg_tag( pfql_ctx, msg_list[CURROW].id);
841 break;
842 case 'b':
843 show_body_win = !show_body_win;
844 win_resize();
845 if ( show_body_win )
846 msg_show_body(0);
847 break;
848 case 'B':
849 show_body_always = !show_body_always;
850 win_header();
851 break;
852 case 32:
853 case 't':
854 if ( !msg_num )
855 break;
856 if ( MSGMARK==-1 ) {
857 pfql_msg_toggletag( pfql_ctx,msg_list[CURROW].id );
858 } else {
859 if ( CURMSG>=MSGMARK ) {
860 for ( i=MSGMARK; i<=CURMSG; i++ )
861 pfql_msg_tag(pfql_ctx,pfql_msg_at(pfql_ctx,i)->id);
862 } else {
863 for ( i=CURMSG; i<=MSGMARK; i++ )
864 pfql_msg_tag(pfql_ctx,pfql_msg_at(pfql_ctx,i)->id);
865 }
866 }
867 MSGMARK = -1;
868 goto_next();
869 queue_force_repaint ( 1 );
870 show_cursor();
871 win_header();
872 break;
873 case 'T':
874 wnd_getregexp();
875 pfql_msg_searchandtag(pfql_ctx,regexps);
876 queue_force_repaint ( 1 );
877 win_header();
878 break;
879 case 'u':
880 pfql_tag_none(pfql_ctx);
881 win_header();
882 queue_force_repaint ( 1 );
883 break;
884 case ':':
885 pfql_getstatus(pfql_ctx)->auto_wrk_tagged = !pfql_getstatus(pfql_ctx)->auto_wrk_tagged;
886 win_header();
887 break;
888 case ';':
889 pfql_getstatus(pfql_ctx)->wrk_tagged = !pfql_getstatus(pfql_ctx)->wrk_tagged;
890 win_header();
891 break;
892 case '/':
893 wnd_getregexp();
894 i = pfql_msg_search(pfql_ctx,regexps);
895 goto_msg ( i );
896 queue_force_repaint ( 1 );
897 break;
898 case 'n':
899 i = pfql_msg_searchnext(pfql_ctx,regexps);
900 goto_msg ( i );
901 break;
902 case 'p':
903 pfql_msg_searchprev(pfql_ctx,regexps);
904 break;
905 case '?':
906 help();
907 queue_force_repaint ( 1 );
908 break;
909 case 'c':
910 pfql_getstatus(pfql_ctx)->ask_confirm = !pfql_getstatus(pfql_ctx)->ask_confirm;
911 win_header();
912 break;
913 case '-':
914 pfql_getstatus(pfql_ctx)->do_scan = !pfql_getstatus(pfql_ctx)->do_scan;
915 win_header();
916 break;
917 case '+':
918 pfql_getstatus(pfql_ctx)->use_colors = !pfql_getstatus(pfql_ctx)->use_colors;
919 queue_force_repaint ( 1 );
920 win_resize();
921 win_header();
922 break;
923 case '>':
924 if ( bwnd_height<LINES-10 )
925 bwnd_height++;
926 win_resize();
927 win_header();
928 break;
929 case '<':
930 if ( bwnd_height>5 )
931 bwnd_height--;
932 win_resize();
933 win_header();
934 break;
935 case ',':
936 if ( show_body_fromline && show_body_win )
937 show_body_fromline--;
938 msg_show_body(0);
939 break;
940 case '.':
941 if ( show_body_win ) {
942 show_body_fromline++;
943 msg_show_body(0);
944 }
945 break;
946 case 13:
947 case 10:
948 msg_show_body(0);
949 if ( !show_body_win ) {
950 win_resize();
951 queue_force_repaint ( 1 );
952 msg_show_headers();
953 }
954 break;
955 case 's':
956 if ( msg_num ) {
957 msg_show_body(1);
958 win_resize();
959 queue_force_repaint ( 1 );
960 msg_show_headers();
961 }
962 break;
963 case 'S':
964 r = wnd_change_sort_field();
965 if ( r != -1 ) {
966 if ( r<=3 ) {
967 pfql_getstatus(pfql_ctx)->sort_field = r;
968 pfql_getstatus(pfql_ctx)->sort_sense = PFQL_SORT_ASC;
969 } else {
970 pfql_getstatus(pfql_ctx)->sort_field = r-3;
971 pfql_getstatus(pfql_ctx)->sort_sense = PFQL_SORT_DESC;
972 }
973 }
974 queue_force_repaint ( 1 );
975 }
976
977 }
978 }
979
main(int argc,char ** argv)980 int main ( int argc, char** argv ) {
981 int opt;
982 int mm;
983
984 if ( getuid()!=0 ) {
985 fprintf ( stderr, "You need to be root to use pfqueue, sorry\n" );
986 exit (-3);
987 }
988
989 pfql_ctx = 0;
990 if ( pfql_context_create (&pfql_ctx)!=PFQL_OK ) {
991 fprintf ( stderr, "pfqueue: cannot pfql_create_context!\n" );
992 exit (-1);
993 }
994
995 if ( pfql_init(pfql_ctx)!=PFQL_OK ) {
996 fprintf ( stderr, "pfqueue: cannot pfql_init!\n" );
997 exit (-1);
998 }
999
1000 if ( !fe_init() ) {
1001 pfql_context_destroy(pfql_ctx);
1002 fe_close();
1003 fprintf ( stderr, "pfqueue: cannot fe_init!\n" );
1004 exit (-2);
1005 }
1006
1007 /* Ignore pipes error */
1008 signal ( SIGPIPE, SIG_IGN );
1009
1010 /*
1011 * Parse parameters
1012 */
1013
1014 // Some defaults
1015 pfql_ctx->regexp = 0;
1016 half_delay_time = 1;
1017 show_body_win = 0;
1018 show_body_always = 1;
1019
1020 pfq_read_config ( pfql_ctx );
1021
1022 opt = 0;
1023 while ( opt!=-1 ) {
1024 opt = getopt ( argc, argv, "p:c:r:B:b:q:s:m:l:ehvn" );
1025 switch (opt) {
1026 case 'p':
1027 snprintf ( pfql_getconf(pfql_ctx)->backend_progs, pfql_getconf(pfql_ctx)->max_char, "%s", optarg );
1028 break;
1029 case 'c':
1030 snprintf ( pfql_getconf(pfql_ctx)->backend_config, pfql_getconf(pfql_ctx)->max_char, "%s", optarg );
1031 break;
1032 case 'r':
1033 snprintf ( pfql_getconf(pfql_ctx)->remote_host, pfql_getconf(pfql_ctx)->max_char, "%s", optarg );
1034 break;
1035 case 'B':
1036 snprintf ( pfql_getconf(pfql_ctx)->backends_path, pfql_getconf(pfql_ctx)->max_char, "%s", optarg );
1037 break;
1038 case 'b':
1039 snprintf ( pfql_getconf(pfql_ctx)->backend_name, pfql_getconf(pfql_ctx)->max_char, "%s", optarg );
1040 break;
1041 case 'q':
1042 mm = atoi ( optarg );
1043 switch ( mm ) {
1044 case 1:
1045 mm = 0;
1046 break;
1047 case 2:
1048 mm = 3;
1049 break;
1050 case 3:
1051 mm = 2;
1052 break;
1053 case 4:
1054 mm = 1;
1055 break;
1056 default:
1057 mm = 0;
1058 }
1059 pfql_getconf(pfql_ctx)->initial_queue = mm;
1060 break;
1061 case 'h':
1062 usage();
1063 exit(0);
1064 break;
1065 case 'v':
1066 version();
1067 exit(0);
1068 break;
1069 case 'm':
1070 mm = atoi (optarg);
1071 if ( mm < 5 )
1072 mm = 5;
1073 pfql_getconf(pfql_ctx)->msg_max = mm;
1074 break;
1075 case 's':
1076 half_delay_time = atoi ( optarg );
1077 if ( half_delay_time > 300 )
1078 half_delay_time = 300;
1079 if ( half_delay_time < 1 )
1080 half_delay_time = 1;
1081 break;
1082 case 'l':
1083 mm = atoi ( optarg );
1084 if ( mm > 300 )
1085 mm = 300;
1086 if ( mm < 1 )
1087 mm = 1;
1088 pfql_getconf(pfql_ctx)->scan_limit = mm;
1089 break;
1090 case 'e':
1091 pfql_getstatus(pfql_ctx)->use_envelope = TRUE;
1092 break;
1093 case 'n':
1094 pfql_getstatus(pfql_ctx)->use_colors = 0;
1095 break;
1096 case 'd':
1097 pfql_getconf(pfql_ctx)->scan_delay = atoi(optarg);
1098 break;
1099 case '?':
1100 goto do_exit;
1101 }
1102 }
1103
1104 if ( pfql_start(pfql_ctx) != PFQL_OK ) {
1105 fprintf ( stderr, "pfqueue: cannot start pfqlib. See syslog for details\n" );
1106 pfql_context_destroy(pfql_ctx);
1107 exit (-4);
1108 }
1109
1110 win_resize();
1111 queue_show();
1112 main_loop();
1113
1114 do_exit:
1115 if ( pfql_ctx )
1116 pfql_context_destroy ( pfql_ctx );
1117 fe_close();
1118 endwin();
1119
1120 return 0;
1121 }
1122
1123