00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef _RSSBGR_CONFIG_H
00023 #define _RSSBGR_CONFIG_H
00024 #include "config.h"
00025 #endif
00026
00027 #include <signal.h>
00028 #include <curses.h>
00029 #include <menu.h>
00030
00031 #include "share.h"
00032 #include "url.h"
00033
00034 #ifndef HAVE_STRLCPY
00035 #include "compat/strlcpy.h"
00036 #endif
00037
00038 struct config_item
00039 {
00040 char *url;
00041 unsigned int freq;
00042 char *action;
00043 };
00044
00045 struct config_item *config = NULL;
00046 unsigned int config_items_count, menu_items_count;
00047
00048 ITEM **config_menu_items;
00049 MENU *config_menu = NULL;
00050 WINDOW *config_menu_win, *edit_win = NULL, *err_url_win = NULL, *help_main_win = NULL, *help_edit_win = NULL;
00051
00052 char *home, *directory, *lockfile, *configfile;
00053 char edit_buffer[3][BUFSIZ];
00054 unsigned short int edit_buffer_index;
00055
00056 void repaint(short int reset);
00057 void repaint_menu(void);
00058 void repaint_edit(void);
00059 void repaint_err_url(void);
00060 void repaint_help_main(void);
00061 void repaint_help_edit(void);
00062 void rebuild_menu();
00063 void edit(void);
00064 void catch_signal(int sig);
00065 void set_signal_handlers(void);
00066 void readconfig(void);
00067 void kill_rssbgr(void);
00068
00069 int main(void)
00070 {
00071 FILE *fd;
00072 char *url, *action;
00073 long int frequency;
00074 int i, c;
00075 directory = (char *)malloc(PATH_MAX);
00076 lockfile = (char *)malloc(PATH_MAX);
00077 configfile = (char *)malloc(PATH_MAX);
00078 home = (char *)getenv("HOME");
00079 if (home == NULL) DIE("HOME variable not set. Program will exit.")
00080 sprintf(directory, "%s/" DIRECTORY, home); directory = (char *)realloc(directory, strlen(directory)+1);
00081 sprintf(lockfile, "%s/" LOCKFILE, home); lockfile = (char *)realloc(lockfile, strlen(lockfile)+1);
00082 sprintf(configfile, "%s/" CONFIGFILE, home); configfile = (char *)realloc(configfile, strlen(configfile)+1);
00083 init_pair(1, COLOR_BLACK, COLOR_WHITE);
00084 init_pair(2, COLOR_WHITE, COLOR_BLACK);
00085 readconfig();
00086 rebuild_menu();
00087 initscr();
00088 repaint(0);
00089 set_signal_handlers();
00090 while ((c = wgetch(config_menu_win)) != 'q')
00091 switch (c)
00092 {
00093
00094 case KEY_PPAGE:
00095 menu_driver(config_menu, REQ_SCR_UPAGE);
00096 break;
00097 case 'k':
00098 case KEY_UP:
00099 menu_driver(config_menu, REQ_UP_ITEM);
00100 break;
00101 case 'j':
00102 case KEY_DOWN:
00103 menu_driver(config_menu, REQ_DOWN_ITEM);
00104 break;
00105 case KEY_NPAGE:
00106 menu_driver(config_menu, REQ_SCR_DPAGE);
00107 break;
00108
00109 case 'd':
00110 case KEY_DC:
00111 if (item_index(current_item(config_menu)))
00112 {
00113 free(config[item_index(current_item(config_menu))-1].url);
00114 free(config[item_index(current_item(config_menu))-1].action);
00115 for (i = item_index(current_item(config_menu)); i < config_items_count; ++i)
00116 {
00117 config[i-1].url = config[i].url;
00118 config[i-1].freq = config[i].freq;
00119 config[i-1].action = config[i].action;
00120 }
00121 --config_items_count;
00122 config = (struct config_item *)realloc(config, config_items_count*sizeof(struct config_item));
00123 rebuild_menu();
00124 repaint(0);
00125 }
00126 break;
00127 case 10:
00128 edit();
00129 break;
00130 case 'K':
00131 kill_rssbgr();
00132 break;
00133 case 'h':
00134 case KEY_F(1):
00135 repaint_help_main();
00136 while(wgetch(help_main_win) != 10);
00137 delwin(help_main_win); help_main_win = NULL;
00138 repaint(0);
00139 }
00140 delwin(edit_win);
00141 delwin(config_menu_win);
00142 endwin();
00143 fprintf(stdout, "Writing new config... ");
00144 fd = fopen(configfile, "w");
00145 if (fd == NULL)
00146 fprintf(stdout, "cannot open %s for writing.\n", configfile);
00147 else
00148 {
00149 for (i = 0; i < config_items_count; ++i)
00150 {
00151 url = config[i].url;
00152 frequency = config[i].freq;
00153 action = config[i].action;
00154 fprintf(fd, CONFIGFILE_FORMAT "\n", CONFIGFILE_VARS_PRINT);
00155 }
00156 fclose(fd);
00157 fprintf(stdout, "OK.\n");
00158 unlink(lockfile);
00159 }
00160 return 0;
00161 }
00162
00163 void repaint(short int reset)
00164 {
00165 int x, y, i;
00166 if (reset)
00167 {
00168 endwin();
00169 refresh();
00170 }
00171 else
00172 {
00173 wnoutrefresh(stdscr);
00174 wnoutrefresh(config_menu_win);
00175 if (edit_win != NULL) wnoutrefresh(edit_win);
00176 }
00177 getmaxyx(stdscr, y, x);
00178 wmove(stdscr, 0, 0);
00179 for (i = 0; i < x*y; i++) wprintw(stdscr, " ");
00180 box(stdscr, 0, 0);
00181 mvwprintw(stdscr, 0, 2, " RSS Background Reader configuration ");
00182 mvwprintw(stdscr, LINES-1, 2, " q - save&quit ");
00183 getyx(stdscr, y, x);
00184 mvwprintw(stdscr, y, x+2, " h, F1 - help ");
00185 wmove(stdscr, 1, 1);
00186 wrefresh(stdscr);
00187 noecho();
00188 cbreak();
00189 repaint_menu();
00190 if (edit_win != NULL) repaint_edit();
00191 if ((edit_win != NULL) && (err_url_win != NULL)) repaint_err_url();
00192 if ((edit_win != NULL) && (err_url_win == NULL) && (help_edit_win != NULL)) repaint_help_edit();
00193 if ((edit_win == NULL) && (help_main_win != NULL)) repaint_help_main();
00194 if (!reset) doupdate();
00195 }
00196
00197 void repaint_menu(void)
00198 {
00199 ITEM *current = current_item(config_menu);
00200 unpost_menu(config_menu);
00201 delwin(config_menu_win);
00202 config_menu_win = newwin(LINES-2, COLS-2, 1, 1);
00203 set_menu_win(config_menu, config_menu_win);
00204 set_menu_sub(config_menu, derwin(config_menu_win, LINES-4, COLS-4, 1, 1));
00205 set_menu_format(config_menu, LINES-4, 1);
00206 set_current_item(config_menu, current);
00207 post_menu(config_menu);
00208 keypad(config_menu_win, TRUE);
00209 wrefresh(config_menu_win);
00210 }
00211
00212 void repaint_edit(void)
00213 {
00214 int x, y, i;
00215 delwin(edit_win);
00216 edit_win = newwin(12, COLS-2, (int)(LINES-12)/2, 1);
00217 box(edit_win, 0, 0);
00218 if (!item_index(current_item(config_menu)))
00219 mvwprintw(edit_win, 0, 2, " Add new RSS feed ");
00220 else
00221 mvwprintw(edit_win, 0, 2, (strlen(config[item_index(current_item(config_menu))-1].url) > 63)?(" Edit: %.60s... "):(" Edit: %.63s "), config[item_index(current_item(config_menu))-1].url);
00222 mvwprintw(edit_win, 11, 2, " Esc - cancel ");
00223 getyx(edit_win, y, x);
00224 mvwprintw(edit_win, y, x+2, " Enter - OK ");
00225 getyx(edit_win, y, x);
00226 mvwprintw(edit_win, y, x+2, " F1, ^F - help ");
00227 mvwprintw(edit_win, 2, 2, "URL:");
00228 wattron(edit_win, A_REVERSE);
00229 wmove(edit_win, 3, 2);
00230 for (i = 0; i < COLS-6; ++i) wprintw(edit_win, " ");
00231 mvwprintw(edit_win, 3, 2, "%s", (strlen(edit_buffer[0]) > COLS-7)?(edit_buffer[0]+strlen(edit_buffer[0])-COLS+7):(edit_buffer[0]));
00232 wattroff(edit_win, A_REVERSE);
00233 mvwprintw(edit_win, 5, 2, "Checking frequency (in seconds):");
00234 wattron(edit_win, A_REVERSE);
00235 wmove(edit_win, 6, 2);
00236 for (i = 0; i < COLS-6; ++i) wprintw(edit_win, " ");
00237 mvwprintw(edit_win, 6, 2, "%s", (strlen(edit_buffer[1]) > COLS-7)?(edit_buffer[1]+strlen(edit_buffer[1])-COLS+7):(edit_buffer[1]));
00238 wattroff(edit_win, A_REVERSE);
00239 mvwprintw(edit_win, 8, 2, "Command (see help (F1) for modifiers):");
00240 wattron(edit_win, A_REVERSE);
00241 wmove(edit_win, 9, 2);
00242 for (i = 0; i < COLS-6; ++i) wprintw(edit_win, " ");
00243 mvwprintw(edit_win, 9, 2, "%s", (strlen(edit_buffer[2]) > COLS-7)?(edit_buffer[2]+strlen(edit_buffer[2])-COLS+7):(edit_buffer[2]));
00244 wattroff(edit_win, A_REVERSE);
00245 wmove(edit_win, 3+3*edit_buffer_index, (strlen(edit_buffer[edit_buffer_index]) > COLS-7)?(COLS-5):(2+strlen(edit_buffer[edit_buffer_index])));
00246 keypad(edit_win, TRUE);
00247 wrefresh(edit_win);
00248 }
00249
00250 void repaint_err_url(void)
00251 {
00252 if (err_url_win != NULL) delwin(err_url_win);
00253 err_url_win = newwin(5, 21, (LINES-5)/2, (COLS-21)/2);
00254 box(err_url_win, 0, 0);
00255 mvwprintw(err_url_win, 0, 2, " Error ");
00256 mvwprintw(err_url_win, 4, 2, " press Enter ");
00257 mvwprintw(err_url_win, 2, 2, "URL is not valid!");
00258 keypad(err_url_win, TRUE);
00259 wrefresh(err_url_win);
00260 }
00261
00262 void repaint_help_main(void)
00263 {
00264 if (help_main_win != NULL) delwin(help_main_win);
00265 help_main_win = newwin(13, 27, (LINES-13)/2, (COLS-27)/2);
00266 box(help_main_win, 0, 0);
00267 mvwprintw(help_main_win, 0, 2, " Help ");
00268 mvwprintw(help_main_win, 11, 2, " press Enter ");
00269 mvwprintw(help_main_win, 2, 2, "UP, k - previous item");
00270 mvwprintw(help_main_win, 3, 2, "DOWN, j - next item");
00271 mvwprintw(help_main_win, 4, 2, "PgUp - scroll up");
00272 mvwprintw(help_main_win, 5, 2, "PgDn - scroll down");
00273 mvwprintw(help_main_win, 6, 2, "Del, d - delete item");
00274 mvwprintw(help_main_win, 7, 2, "F1, h - help");
00275 mvwprintw(help_main_win, 8, 2, "Enter - add/edit item");
00276 mvwprintw(help_main_win, 9, 2, "q - save & quit");
00277 mvwprintw(help_main_win, 10, 2, "K - kill RSSbgr");
00278 keypad(help_main_win, TRUE);
00279 wrefresh(help_main_win);
00280 }
00281
00282 void repaint_help_edit(void)
00283 {
00284 if (help_edit_win != NULL) delwin(help_edit_win);
00285 help_edit_win = newwin(13, 37, (LINES-13)/2, (COLS-37)/2);
00286 box(help_edit_win, 0, 0);
00287 mvwprintw(help_edit_win, 0, 2, " Help ");
00288 mvwprintw(help_edit_win, 12, 2, " press Enter ");
00289 mvwprintw(help_edit_win, 2, 2, "Command modifiers:");
00290 mvwprintw(help_edit_win, 3, 2, "{T} - feed title");
00291 mvwprintw(help_edit_win, 4, 2, "{D} - feed description");
00292 mvwprintw(help_edit_win, 5, 2, "{L} - feed main link");
00293 mvwprintw(help_edit_win, 6, 2, "{t} - new information title");
00294 mvwprintw(help_edit_win, 7, 2, "{d} - new information description");
00295 mvwprintw(help_edit_win, 8, 2, "{l} - new information link");
00296 mvwprintw(help_edit_win, 9, 2, "\\} - char }");
00297 mvwprintw(help_edit_win, 10, 2, "\\{ is leaved unchanged");
00298 keypad(help_edit_win, TRUE);
00299 wrefresh(help_edit_win);
00300 }
00301 void rebuild_menu(void)
00302 {
00303 int i;
00304 if (config_menu != NULL)
00305 {
00306 unpost_menu(config_menu);
00307 free_menu(config_menu);
00308 for (i = 0; i < menu_items_count; ++i)
00309 free_item(config_menu_items[i]);
00310 free(config_menu_items);
00311 }
00312 menu_items_count = config_items_count+2;
00313 config_menu_items = (ITEM **)calloc(menu_items_count, sizeof(ITEM *));
00314 config_menu_items[0] = new_item("<add new RSS feed>", "<add new RSS feed>");
00315 for (i = 1; i <= config_items_count; ++i)
00316 config_menu_items[i] = new_item(config[i-1].url, config[i-1].url);
00317 config_menu_items[config_items_count+1] = new_item(NULL, NULL);
00318 config_menu = new_menu(config_menu_items);
00319 menu_opts_off(config_menu, O_SHOWDESC | O_NONCYCLIC);
00320 set_menu_mark(config_menu, " > ");
00321 }
00322
00323 void edit(void)
00324 {
00325 int c, p, i;
00326 long int frequency;
00327 char *host, *request;
00328 uint16_t port;
00329
00330 if (item_index(current_item(config_menu)))
00331 {
00332 strcpy(edit_buffer[0], config[item_index(current_item(config_menu))-1].url);
00333 sprintf(edit_buffer[1], "%d", config[item_index(current_item(config_menu))-1].freq);
00334 strcpy(edit_buffer[2], config[item_index(current_item(config_menu))-1].action);
00335 }
00336 else
00337 {
00338 strcpy(edit_buffer[0], "");
00339 sprintf(edit_buffer[1], "%d", MIN_FREQUENCY);
00340 strcpy(edit_buffer[2], "");
00341 }
00342 edit_win = newwin(12, COLS-2, (int)(LINES-12)/2, 1);
00343 start:
00344 edit_buffer_index = 0;
00345 repaint(0);
00346 while(((c = wgetch(edit_win)) != 27) && (c != 10))
00347 {
00348 switch (c)
00349 {
00350 case KEY_UP:
00351 edit_buffer_index = (edit_buffer_index == 0)?(2):(edit_buffer_index-1);
00352 wmove(edit_win, 3+3*edit_buffer_index, (strlen(edit_buffer[edit_buffer_index]) > COLS-7)?(COLS-5):(2+strlen(edit_buffer[edit_buffer_index])));
00353 break;
00354 case 9:
00355 case KEY_DOWN:
00356 edit_buffer_index = (edit_buffer_index+1)%3;
00357 wmove(edit_win, 3+3*edit_buffer_index, (strlen(edit_buffer[edit_buffer_index]) > COLS-7)?(COLS-5):(2+strlen(edit_buffer[edit_buffer_index])));
00358 break;
00359 case KEY_BACKSPACE:
00360 case 127:
00361 p = strlen(edit_buffer[edit_buffer_index]);
00362 if (p) edit_buffer[edit_buffer_index][p-1] = '\0';
00363 wattron(edit_win, A_REVERSE);
00364 wmove(edit_win, 3+3*edit_buffer_index, 2);
00365 for (i = 0; i < COLS-6; ++i) wprintw(edit_win, " ");
00366 mvwprintw(edit_win, 3+3*edit_buffer_index, 2, "%s", (strlen(edit_buffer[edit_buffer_index]) > COLS-7)?(edit_buffer[edit_buffer_index]+strlen(edit_buffer[edit_buffer_index])-COLS+7):(edit_buffer[edit_buffer_index]));
00367 wattroff(edit_win, A_REVERSE);
00368 break;
00369 case 6:
00370 case KEY_F(1):
00371 repaint_help_edit();
00372 while(wgetch(help_edit_win) != 10);
00373 delwin(help_edit_win); help_edit_win = NULL;
00374 repaint(0);
00375 break;
00376 default:
00377 p = strlen(edit_buffer[edit_buffer_index]);
00378 if ((c < ' ') || (c > 255) || (p+1 >= BUFSIZ)) break;
00379 edit_buffer[edit_buffer_index][p] = (char)(c & 0x000000FF);
00380 edit_buffer[edit_buffer_index][p+1] = '\0';
00381 wattron(edit_win, A_REVERSE);
00382 mvwprintw(edit_win, 3+3*edit_buffer_index, 2, "%s", (strlen(edit_buffer[edit_buffer_index]) > COLS-7)?(edit_buffer[edit_buffer_index]+strlen(edit_buffer[edit_buffer_index])-COLS+7):(edit_buffer[edit_buffer_index]));
00383 wattroff(edit_win, A_REVERSE);
00384 }
00385 wrefresh(edit_win);
00386 }
00387 if (c == 10)
00388 {
00389 if (!strlen(edit_buffer[0]) || parse_url(edit_buffer[0], &host, &port, &request) == -1)
00390 {
00391 free(host); free(request);
00392 repaint_err_url();
00393 while(wgetch(err_url_win) != 10);
00394 delwin(err_url_win); err_url_win = NULL;
00395 goto start;
00396 }
00397 free(host); free(request);
00398 if (item_index(current_item(config_menu)))
00399 {
00400 config[item_index(current_item(config_menu))-1].url = (char *)realloc(config[item_index(current_item(config_menu))-1].url, strlen(edit_buffer[0])+1);
00401 strcpy(config[item_index(current_item(config_menu))-1].url, edit_buffer[0]);
00402 frequency = strtol(edit_buffer[1], (char **)NULL, 10);
00403 frequency = (frequency < 0)?(-frequency):(frequency);
00404 config[item_index(current_item(config_menu))-1].freq = ((frequency < MIN_FREQUENCY)?(MIN_FREQUENCY):(frequency));
00405 config[item_index(current_item(config_menu))-1].action = (char *)realloc(config[item_index(current_item(config_menu))-1].action, strlen(edit_buffer[2])+1);
00406 strcpy(config[item_index(current_item(config_menu))-1].action, edit_buffer[2]);
00407 }
00408 else
00409 {
00410 ++config_items_count;
00411 config = (struct config_item *)realloc(config, config_items_count*sizeof(struct config_item));
00412 config[config_items_count-1].url = (char *)malloc(strlen(edit_buffer[0])+1);
00413 strcpy(config[config_items_count-1].url, edit_buffer[0]);
00414 frequency = strtol(edit_buffer[1], (char **)NULL, 10);
00415 frequency = (frequency < 0)?(-frequency):(frequency);
00416 config[config_items_count-1].freq = ((frequency < MIN_FREQUENCY)?(MIN_FREQUENCY):(frequency));
00417 config[config_items_count-1].action = (char *)malloc(strlen(edit_buffer[2])+1);
00418 strcpy(config[config_items_count-1].action, edit_buffer[2]);
00419 }
00420 rebuild_menu();
00421 }
00422 delwin(edit_win); edit_win = NULL;
00423 repaint(0);
00424 }
00425
00426 void catch_signal(int sig)
00427 {
00428 if (sig != SIGWINCH) return;
00429 repaint(1);
00430 }
00431
00432 void set_signal_handlers(void)
00433 {
00434 struct sigaction sa;
00435 sa.sa_handler = catch_signal;
00436 sigemptyset(&sa.sa_mask);
00437 sa.sa_flags = 0;
00438 sigaction(SIGWINCH, &sa, NULL);
00439 }
00440
00441 void readconfig(void)
00442 {
00443 FILE *fd;
00444 char *line, *url, *action, *a, *host, *request;
00445 long int frequency;
00446 uint16_t port;
00447
00448 config_items_count = 0;
00449 config = (struct config_item *)malloc(config_items_count*sizeof(struct config_item));
00450 line = (char *)malloc(BUFSIZ);
00451 url = (char *)malloc(BUFSIZ);
00452 action = (char *)malloc(BUFSIZ);
00453 fd = fopen(configfile, "r");
00454 if (fd == NULL)
00455 return;
00456 while(!feof(fd))
00457 {
00458 if (fgets(line, BUFSIZ, fd))
00459 {
00460 if (sscanf(line, CONFIGFILE_FORMAT "\n", CONFIGFILE_VARS_SCAN) != 3) continue;
00461 a = strchr(strchr(line, '\t')+1, '\t')+1;
00462 strlcpy(action, a, strchr(a, '\n')-a+1);
00463 ++config_items_count;
00464 config = (struct config_item *)realloc(config, config_items_count*sizeof(struct config_item));
00465 config[config_items_count-1].url = (char *)malloc(strlen(url)+1);
00466 strcpy(config[config_items_count-1].url, url);
00467 frequency = (frequency < 0)?(-frequency):(frequency);
00468 frequency = ((frequency < MIN_FREQUENCY)?(MIN_FREQUENCY):(frequency));
00469 config[config_items_count-1].freq = frequency;
00470 if (parse_url(url, &host, &port, &request) == -1)
00471 {
00472 free(host); free(request);
00473 --config_items_count;
00474 config = (struct config_item *)realloc(config, config_items_count*sizeof(struct config_item));
00475 continue;
00476 }
00477 config[config_items_count-1].action = (char *)malloc(strlen(action)+1);
00478 strcpy(config[config_items_count-1].action, action);
00479 }
00480 }
00481 fclose(fd);
00482 free(line); free(url); free(action);
00483 }
00484
00485 void kill_rssbgr(void)
00486 {
00487 FILE *lockfile_s;
00488 unsigned int rssbgr_pid;
00489 if (((lockfile_s = fopen(lockfile, "r")) != NULL) && (fscanf(lockfile_s, "%u", &rssbgr_pid) == 1) && (rssbgr_pid > 0))
00490 kill(rssbgr_pid, SIGTERM);
00491 if (lockfile_s != NULL) fclose(lockfile_s);
00492 }