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