PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/rclock/rconf/rconf.c

#
C | 1129 lines | 845 code | 219 blank | 65 comment | 329 complexity | 4d75606a7c58f588868dfe2c4ed1236c MD5 | raw file
  1. /*
  2. * Copyright (c) 1999 Chris Wareham. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. The name of the author may not be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  20. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  24. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  25. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. * POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <unistd.h>
  33. #include <pwd.h>
  34. #include <regex.h>
  35. #include <sys/types.h>
  36. #include <sys/param.h>
  37. #include <X11/Intrinsic.h>
  38. #include <X11/IntrinsicP.h> /* for XtConfigureWidget and XtResizeWidget */
  39. #include <X11/StringDefs.h>
  40. #include <X11/Shell.h>
  41. #include <X11/Xaw/Box.h>
  42. #include <X11/Xaw/Command.h>
  43. #include <X11/Xaw/Dialog.h>
  44. #include <X11/Xaw/Form.h>
  45. #include <X11/Xaw/Label.h>
  46. #include <X11/Xaw/List.h>
  47. #include <X11/Xaw/Toggle.h>
  48. #include <X11/Xaw/Viewport.h>
  49. #include "list.h"
  50. #include "dialogs.h"
  51. #include "edit.h"
  52. #include "rconf.h"
  53. static void create_interface(Interface *);
  54. static void populate_interface(Interface *);
  55. static char *format_line(Entry *);
  56. static void add_cb(Widget, XtPointer, XtPointer);
  57. static void modify_cb(Widget, XtPointer, XtPointer);
  58. static void editok_cb(Widget, XtPointer, XtPointer);
  59. static void editcancel_cb(Widget, XtPointer, XtPointer);
  60. static void delete_cb(Widget, XtPointer, XtPointer);
  61. static void deleteyes_cb(Widget, XtPointer, XtPointer);
  62. static void deleteno_cb(Widget, XtPointer, XtPointer);
  63. static void close_cb(Widget, XtPointer, XtPointer);
  64. static void warning_cb(Widget, XtPointer, XtPointer);
  65. static void error_cb(Widget, XtPointer, XtPointer);
  66. static char *get_text(Widget);
  67. static FILE *open_config(void);
  68. static void read_config(FILE *, List *);
  69. static char *get_line(FILE *);
  70. static char *trim_string(char *);
  71. static int write_config(List *);
  72. static char *defaults[] = {
  73. #include "RConf_ad.h"
  74. NULL
  75. };
  76. int
  77. main(int argc, char *argv[])
  78. {
  79. char *progname, *ptr;
  80. XtAppContext app_context;
  81. Interface ui;
  82. FILE *fp;
  83. progname = argv[0];
  84. if ((ptr = strrchr(progname, '/')))
  85. progname = ptr + 1;
  86. argv[0] = "rconf";
  87. XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL);
  88. ui.toplevel = XtAppInitialize(&app_context, "RConf",
  89. NULL, 0, &argc, argv, defaults, NULL, 0);
  90. ui.entries_changed = FALSE;
  91. ui.entries = list_init(NULL);
  92. create_interface(&ui);
  93. if ((fp = open_config()) == NULL) {
  94. message_dialog(ui.dialog, "Unable to create config file", error_cb, NULL);
  95. XtAppMainLoop(app_context);
  96. }
  97. read_config(fp, ui.entries);
  98. fclose(fp);
  99. populate_interface(&ui);
  100. XtAppMainLoop(app_context);
  101. return 0;
  102. }
  103. FILE *
  104. open_config(void)
  105. {
  106. char *ptr, path[MAXPATHLEN];
  107. struct passwd *pwent;
  108. FILE *fp;
  109. if ((ptr = getenv("HOME")) == NULL) {
  110. pwent = getpwuid(getuid());
  111. ptr = pwent->pw_dir;
  112. }
  113. snprintf(path, MAXPATHLEN, "%s/%s", ptr, CONFIGFILE);
  114. if ((fp = fopen(path, "r+")) == NULL) {
  115. if ((fp = fopen(path, "w+")) == NULL)
  116. return NULL;
  117. }
  118. return fp;
  119. }
  120. void
  121. read_config(FILE *fp, List *entries)
  122. {
  123. char *ptr, *line;
  124. regex_t days_preg, msg_preg, prog_preg;
  125. regmatch_t pmatch[2];
  126. Entry *entry;
  127. int found_time;
  128. regcomp(&days_preg, "^([mtwrfsu]{1,7}) *", REG_EXTENDED);
  129. regcomp(&msg_preg, "^ *([^;]+)", REG_EXTENDED);
  130. regcomp(&prog_preg, "^; *(.+)$", REG_EXTENDED);
  131. while ((line = get_line(fp))) {
  132. ptr = trim_string(line);
  133. if (strlen(ptr) == 0) {
  134. free(line);
  135. continue;
  136. }
  137. #ifdef DEBUG
  138. printf("\n%s\n", ptr);
  139. #endif /* DEBUG */
  140. found_time = FALSE;
  141. entry = calloc(1, sizeof(Entry));
  142. if (sscanf(ptr, "%d:%d ", &entry->hh, &entry->mm) == 2) {
  143. found_time = TRUE;
  144. } else if (sscanf(ptr, "%d:* ", &entry->hh) == 1) {
  145. entry->mm = -1;
  146. found_time = TRUE;
  147. } else if (sscanf(ptr, "*:%d ", &entry->mm) == 1) {
  148. entry->hh = -1;
  149. found_time = TRUE;
  150. } else if (strncmp(ptr, "*:* ", 4) == 0) {
  151. entry->hh = entry->mm = -1;
  152. found_time = TRUE;
  153. } else {
  154. entry->hh = entry->mm = -1;
  155. }
  156. while (*ptr != ' ' && *ptr != ';')
  157. ptr++;
  158. #ifdef DEBUG
  159. printf("Time : '%02d:%02d'\n", entry->hh, entry->mm);
  160. #endif /* DEBUG */
  161. /* days and date can only be specified if time is specified */
  162. if (found_time && *ptr != ';') {
  163. while (*ptr == ' ')
  164. ptr++;
  165. if (strncmp(ptr, "* ", 2) == 0) {
  166. strcpy(entry->days, "*");
  167. ptr++;
  168. } else if (regexec(&days_preg, ptr, 2, pmatch, 0) == 0) {
  169. strncpy(entry->days, ptr + pmatch[1].rm_so,
  170. pmatch[1].rm_eo - pmatch[1].rm_so);
  171. entry->days[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
  172. ptr += pmatch[1].rm_eo;
  173. }
  174. #ifdef DEBUG
  175. if (strlen(entry->days))
  176. printf("Days : '%s'\n", entry->days);
  177. #endif /* DEBUG */
  178. while (*ptr == ' ')
  179. ptr++;
  180. if (sscanf(ptr, "%d/%d/%d ", &entry->month, &entry->day, &entry->year) == 3) {
  181. /* fully specified date */
  182. } else if (sscanf(ptr, "*/%d/%d ", &entry->day, &entry->year) == 2) {
  183. entry->month = -1;
  184. } else if (sscanf(ptr, "%d/*/%d ", &entry->month, &entry->year) == 2) {
  185. entry->day = -1;
  186. } else if (sscanf(ptr, "%d/%d/* ", &entry->month, &entry->day) == 2) {
  187. entry->year = -1;
  188. } else if (sscanf(ptr, "%d/*/* ", &entry->month) == 1) {
  189. entry->day = entry->year = -1;
  190. } else if (sscanf(ptr, "*/%d/* ", &entry->day) == 1) {
  191. entry->month = entry->year = -1;
  192. } else if (sscanf(ptr, "*/*/%d ", &entry->year) == 1) {
  193. entry->month = entry->day = -1;
  194. } else if (strncmp(ptr, "* ", 2) == 0) {
  195. entry->day = entry->month = entry->year = -1;
  196. } else {
  197. entry->day = entry->month = entry->year = -1;
  198. }
  199. #ifdef DEBUG
  200. printf("Date : '%02d/%02d/%d'\n", entry->month, entry->day, entry->year);
  201. #endif /* DEBUG */
  202. while (*ptr != ' ')
  203. ptr++;
  204. }
  205. while (*ptr == ' ')
  206. ptr++;
  207. if (regexec(&msg_preg, ptr, 2, pmatch, 0) == 0) {
  208. entry->message = malloc(pmatch[1].rm_eo - pmatch[1].rm_so + 1);
  209. strncpy(entry->message, ptr + pmatch[1].rm_so,
  210. pmatch[1].rm_eo - pmatch[1].rm_so);
  211. entry->message[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
  212. ptr += pmatch[1].rm_eo;
  213. #ifdef DEBUG
  214. printf("Message : '%s'\n", entry->message);
  215. #endif /* DEBUG */
  216. }
  217. if (regexec(&prog_preg, ptr, 2, pmatch, 0) == 0) {
  218. entry->program = malloc(pmatch[1].rm_eo - pmatch[1].rm_so + 1);
  219. strncpy(entry->program, ptr + pmatch[1].rm_so,
  220. pmatch[1].rm_eo - pmatch[1].rm_so);
  221. entry->program[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
  222. #ifdef DEBUG
  223. printf("Program : '%s'\n", entry->program);
  224. #endif /* DEBUG */
  225. }
  226. /* a message or program must be specified for this entry to be valid */
  227. if(entry->message || entry->program) {
  228. if (entry->hh > 23 || entry->hh < -1)
  229. entry->hh = -1;
  230. if (entry->mm > 59 || entry->mm < -1)
  231. entry->mm = -1;
  232. if (entry->day > 31 || entry->day < 1)
  233. entry->day = -1;
  234. if (entry->month > 12 || entry->month < 1)
  235. entry->month = -1;
  236. if (entry->year > 9999 || entry->year < 1)
  237. entry->year = -1;
  238. list_add(entries, entry);
  239. } else
  240. free(entry);
  241. free(line);
  242. }
  243. regfree(&days_preg);
  244. regfree(&msg_preg);
  245. regfree(&prog_preg);
  246. }
  247. char *
  248. get_line(FILE *fp)
  249. {
  250. char *line, *ptr, buf[BUFSIZ];
  251. if ((line = malloc(BUFSIZ)) == NULL)
  252. return NULL;
  253. if ((fgets(line, BUFSIZ, fp)) == NULL) {
  254. free(line);
  255. return NULL;
  256. }
  257. while (line[strlen(line) - 1] != '\n') {
  258. if(feof(fp))
  259. break;
  260. fgets(buf, BUFSIZ, fp);
  261. if((ptr = realloc(line, strlen(line) + BUFSIZ)) == NULL) {
  262. free(line);
  263. return NULL;
  264. }
  265. line = ptr;
  266. ptr = line + strlen(line);
  267. strcpy(ptr, buf);
  268. }
  269. if (line[strlen(line) - 1] == '\n')
  270. line[strlen(line) - 1] = '\0';
  271. return line;
  272. }
  273. char *
  274. trim_string(char *str)
  275. {
  276. unsigned int n;
  277. if (str == NULL || *str == '\0')
  278. return str;
  279. while (*str && isspace(*str))
  280. str++;
  281. for (n = strlen(str) - 1; n >= 0 && isspace(str[n]); n--)
  282. str[n] = '\0';
  283. for (n = 0; n < strlen(str); n++) {
  284. if (str[n] == '#') {
  285. str[n] = '\0';
  286. break;
  287. }
  288. }
  289. return str;
  290. }
  291. int
  292. write_config(List *entries)
  293. {
  294. char *ptr, path[MAXPATHLEN];
  295. struct passwd *pwent;
  296. FILE *fp;
  297. struct list_node *walker;
  298. Entry *entry;
  299. int len, i;
  300. if ((ptr = getenv("HOME")) == NULL) {
  301. pwent = getpwuid(getuid());
  302. ptr = pwent->pw_dir;
  303. }
  304. snprintf(path, MAXPATHLEN, "%s/%s", ptr, CONFIGFILE);
  305. if ((fp = fopen(path, "w+")) == NULL)
  306. return 1;
  307. for (walker = entries->first; walker; walker = walker->next) {
  308. entry = (Entry *)walker->data;
  309. /* write out time */
  310. if (entry->hh != -1 || entry->mm != -1) {
  311. if (entry->hh == -1)
  312. fprintf(fp, " *:");
  313. else
  314. fprintf(fp, "%02d:", entry->hh);
  315. if (entry->mm == -1)
  316. fprintf(fp, "* ");
  317. else
  318. fprintf(fp, "%02d ", entry->mm);
  319. }
  320. /* write out days */
  321. if ((len = strlen(entry->days))) {
  322. fprintf(fp, "%s", entry->days);
  323. for (i = len; i < 8; i++)
  324. fputc(' ', fp);
  325. }
  326. /* write out date */
  327. if (len && entry->month == -1 && entry->day == -1 && entry->year == -1) {
  328. fprintf(fp, "* ");
  329. } else if (entry->month != -1 || entry->day != -1 || entry->year != -1) {
  330. if (entry->month == -1)
  331. fprintf(fp, "*/");
  332. else
  333. fprintf(fp, "%02d/", entry->month);
  334. if (entry->day == -1)
  335. fprintf(fp, "*/");
  336. else
  337. fprintf(fp, "%02d/", entry->day);
  338. if (entry->year == -1)
  339. fprintf(fp, "* ");
  340. else
  341. fprintf(fp, "%04d ", entry->year);
  342. if (entry->month == -1)
  343. fputc(' ', fp);
  344. if (entry->day == -1)
  345. fputc(' ', fp);
  346. }
  347. if (entry->message)
  348. fprintf(fp, "%s", entry->message);
  349. if (entry->program)
  350. fprintf(fp, "; %s", entry->program);
  351. fputc('\n', fp);
  352. }
  353. fclose(fp);
  354. return 0;
  355. }
  356. void
  357. create_interface(Interface *ui)
  358. {
  359. char buf[64];
  360. ui->edit_dialog = NULL;
  361. ui->dialog = XtVaCreatePopupShell("dialog", sessionShellWidgetClass, ui->toplevel,
  362. NULL);
  363. ui->form = XtVaCreateManagedWidget("form", formWidgetClass, ui->dialog,
  364. XtNtop, XtChainTop,
  365. XtNleft, XtChainLeft,
  366. XtNright, XtChainRight,
  367. NULL);
  368. ui->label1 = XtVaCreateManagedWidget("label1", labelWidgetClass, ui->form,
  369. XtNtop, XtChainTop,
  370. XtNleft, XtChainLeft,
  371. XtNright, XtChainRight,
  372. NULL);
  373. snprintf(buf, sizeof(buf), "RConf v%d.%d", MAJOR_VERSION, MINOR_VERSION);
  374. XtVaSetValues(ui->label1, XtNlabel, buf, NULL);
  375. ui->label2 = XtVaCreateManagedWidget("label2", labelWidgetClass, ui->form,
  376. XtNfromVert, ui->label1,
  377. XtNleft, XtChainLeft,
  378. XtNright, XtChainRight,
  379. NULL);
  380. XtVaSetValues(ui->label2, XtNlabel, "(C) Chris Wareham 1999", NULL);
  381. ui->subform = XtVaCreateManagedWidget("subform", formWidgetClass, ui->form,
  382. XtNfromVert, ui->label2,
  383. XtNleft, XtChainLeft,
  384. XtNright, XtChainRight,
  385. XtNresizable, True,
  386. NULL);
  387. ui->viewport = XtVaCreateManagedWidget("viewport", viewportWidgetClass, ui->subform,
  388. XtNtop, XtChainTop,
  389. XtNleft, XtChainLeft,
  390. XtNright, XtChainRight,
  391. XtNallowVert, TRUE,
  392. XtNallowHoriz, TRUE,
  393. XtNforceBars, TRUE,
  394. NULL);
  395. ui->list = XtVaCreateManagedWidget("list", listWidgetClass, ui->viewport,
  396. XtNverticalList, TRUE,
  397. XtNdefaultColumns, 1,
  398. NULL);
  399. ui->box = XtVaCreateManagedWidget("box", boxWidgetClass, ui->form,
  400. XtNfromVert, ui->subform,
  401. XtNleft, XtChainLeft,
  402. XtNright, XtChainRight,
  403. XtNbottom, XtChainBottom,
  404. XtNorientation, XtEhorizontal,
  405. NULL);
  406. ui->add_button = XtVaCreateManagedWidget("add", commandWidgetClass, ui->box,
  407. NULL);
  408. XtAddCallback(ui->add_button, XtNcallback, add_cb, ui);
  409. ui->modify_button = XtVaCreateManagedWidget("modify", commandWidgetClass, ui->box,
  410. NULL);
  411. XtAddCallback(ui->modify_button, XtNcallback, modify_cb, ui);
  412. ui->delete_button = XtVaCreateManagedWidget("delete", commandWidgetClass, ui->box,
  413. NULL);
  414. XtAddCallback(ui->delete_button, XtNcallback, delete_cb, ui);
  415. ui->close_button = XtVaCreateManagedWidget("close", commandWidgetClass, ui->box,
  416. NULL);
  417. XtAddCallback(ui->close_button, XtNcallback, close_cb, ui);
  418. }
  419. void
  420. populate_interface(Interface *ui)
  421. {
  422. Entry *entry;
  423. struct list_node *walker;
  424. char **strings;
  425. int i = 0, len = list_length(ui->entries);
  426. Dimension x = 0, y = 0, w = 0, h = 0, bw = 0, w2 = 0;
  427. strings = calloc(len > 0 ? len : 1, sizeof(char *));
  428. for (walker = ui->entries->first; walker; walker = walker->next) {
  429. entry = (Entry *)walker->data;
  430. strings[i] = format_line(entry);
  431. i++;
  432. }
  433. XtRealizeWidget(ui->dialog);
  434. XtVaSetValues(ui->list,
  435. XtNlist, strings,
  436. XtNnumberStrings, len,
  437. NULL);
  438. /* centre align widgets */
  439. XtVaGetValues(ui->subform,
  440. XtNwidth, &w,
  441. XtNheight, &h,
  442. XtNborderWidth, &bw,
  443. NULL);
  444. XtVaGetValues(ui->box,
  445. XtNwidth, &w2,
  446. NULL);
  447. if (w2 != w)
  448. XtResizeWidget(ui->subform, w2, h, bw);
  449. XtVaGetValues(ui->viewport,
  450. XtNx, &x,
  451. XtNy, &y,
  452. XtNheight, &h,
  453. XtNborderWidth, &bw,
  454. NULL);
  455. XtConfigureWidget(ui->viewport, x, y, w2 - x - x, h, bw);
  456. XtVaGetValues(ui->label1,
  457. XtNwidth, &w,
  458. XtNheight, &h,
  459. XtNborderWidth, &bw,
  460. NULL);
  461. if (w2 != w)
  462. XtResizeWidget(ui->label1, w2, h, bw);
  463. XtVaGetValues(ui->label2,
  464. XtNwidth, &w,
  465. XtNheight, &h,
  466. XtNborderWidth, &bw,
  467. NULL);
  468. if (w2 != w)
  469. XtResizeWidget(ui->label2, w2, h, bw);
  470. /* put the whole mess onto the screen */
  471. XtPopup(ui->dialog, XtGrabNone);
  472. XMapRaised(XtDisplay(ui->dialog), XtWindow(ui->dialog));
  473. }
  474. char *
  475. format_line(Entry *entry)
  476. {
  477. int size, i;
  478. char *line;
  479. /* length based on:
  480. *
  481. * 7 bytes for time and subsequent whitespace
  482. * 12 bytes for date and subsequent whitespace
  483. * 9 bytes for days and subsequent whitespace
  484. * n bytes for message and program
  485. * 2 bytes for whitespace between message and program
  486. * 1 byte for terminating null
  487. */
  488. size = 31 + (entry->message ? strlen(entry->message) : 0) +
  489. (entry->program ? strlen(entry->program) : 0);
  490. line = calloc(size, 1);
  491. snprintf(line, size, "%02d:%02d %02d/%02d/%04d %s", entry->hh, entry->mm,
  492. entry->month, entry->day, entry->year, entry->days);
  493. /* time */
  494. if (entry->hh == -1)
  495. memset(line, '*', 2);
  496. if (entry->mm == -1)
  497. memset(line + 3, '*', 2);
  498. /* date */
  499. if (entry->month == -1)
  500. memset(line + 7, '*', 2);
  501. if (entry->day == -1)
  502. memset(line + 10, '*', 2);
  503. if (entry->year == -1)
  504. memset(line + 13, '*', 4);
  505. /* days */
  506. for (i = strlen(entry->days); i < 7; i++)
  507. line[19 + i] = ' ';
  508. /* message */
  509. if (entry->message && strlen(entry->message)) {
  510. strcat(line, " ");
  511. strcat(line, entry->message);
  512. }
  513. /* program */
  514. if (entry->program && strlen(entry->program)) {
  515. strcat(line, " ");
  516. strcat(line, entry->program);
  517. }
  518. return line;
  519. }
  520. void
  521. add_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  522. {
  523. Interface *ui = (Interface *)client_data;
  524. int pw, w, h, bw;
  525. /* if it's the first time through, create the dialog and callbacks */
  526. if (!ui->edit_dialog) {
  527. ui->edit_dialog = create_edit_dialog(ui->toplevel);
  528. XtAddCallback(ui->edit_dialog->ok, XtNcallback, editok_cb,
  529. ui);
  530. XtAddCallback(ui->edit_dialog->cancel, XtNcallback, editcancel_cb,
  531. ui->edit_dialog->dialog);
  532. }
  533. ui->selected_entry = -1;
  534. /* setup dialog strings */
  535. XtVaSetValues(ui->edit_dialog->time,
  536. XtNvalue, "**:**",
  537. NULL);
  538. XtVaSetValues(ui->edit_dialog->date,
  539. XtNvalue, "**/**/****",
  540. NULL);
  541. XtVaSetValues(ui->edit_dialog->message,
  542. XtNvalue, "",
  543. NULL);
  544. XtVaSetValues(ui->edit_dialog->program,
  545. XtNvalue, "",
  546. NULL);
  547. /* unset all toggles */
  548. XtVaSetValues(ui->edit_dialog->mon, XtNstate, FALSE, NULL);
  549. XtVaSetValues(ui->edit_dialog->tue, XtNstate, FALSE, NULL);
  550. XtVaSetValues(ui->edit_dialog->wed, XtNstate, FALSE, NULL);
  551. XtVaSetValues(ui->edit_dialog->thu, XtNstate, FALSE, NULL);
  552. XtVaSetValues(ui->edit_dialog->fri, XtNstate, FALSE, NULL);
  553. XtVaSetValues(ui->edit_dialog->sat, XtNstate, FALSE, NULL);
  554. XtVaSetValues(ui->edit_dialog->sun, XtNstate, FALSE, NULL);
  555. /* centre align label */
  556. XtRealizeWidget(ui->edit_dialog->dialog);
  557. XtVaGetValues(ui->edit_dialog->form,
  558. XtNwidth, &pw,
  559. NULL);
  560. XtVaGetValues(ui->edit_dialog->label,
  561. XtNwidth, &w,
  562. XtNheight, &h,
  563. XtNborderWidth, &bw,
  564. NULL);
  565. if (w != pw)
  566. XtResizeWidget(ui->edit_dialog->label, pw, h, bw);
  567. /* put the whole mess onto the screen */
  568. XtPopup(ui->edit_dialog->dialog, XtGrabExclusive);
  569. XMapRaised(XtDisplay(ui->edit_dialog->dialog),
  570. XtWindow(ui->edit_dialog->dialog));
  571. }
  572. void
  573. modify_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  574. {
  575. XawListReturnStruct *list_selection;
  576. Interface *ui = (Interface *)client_data;
  577. Entry *entry;
  578. char time[6], date[11];
  579. int pw, w, h, bw;
  580. /* ensure something's selected in the list widget */
  581. list_selection = XawListShowCurrent(ui->list);
  582. ui->selected_entry = list_selection->list_index;
  583. if (ui->selected_entry < 0) {
  584. message_dialog(ui->dialog, "Please select an entry to modify",
  585. warning_cb, NULL);
  586. return;
  587. }
  588. entry = list_get(ui->entries, ui->selected_entry);
  589. /* if it's the first time through, create the dialog and callbacks */
  590. if (!ui->edit_dialog) {
  591. ui->edit_dialog = create_edit_dialog(ui->toplevel);
  592. XtAddCallback(ui->edit_dialog->ok, XtNcallback, editok_cb,
  593. ui);
  594. XtAddCallback(ui->edit_dialog->cancel, XtNcallback, editcancel_cb,
  595. ui->edit_dialog->dialog);
  596. }
  597. /* setup dialog strings */
  598. if (entry->hh == -1 && entry->mm == -1)
  599. strcpy(time, "**:**");
  600. else if (entry->hh == -1)
  601. snprintf(time, sizeof(time), "**:%02d", entry->mm);
  602. else if (entry->mm == -1)
  603. snprintf(time, sizeof(time), "%02d:**", entry->hh);
  604. else
  605. snprintf(time, sizeof(time), "%02d:%02d", entry->hh, entry->mm);
  606. if (entry->month == -1 && entry->day == -1 && entry->year == -1)
  607. strcpy(date, "**/**/****");
  608. else if (entry->month == -1 && entry->day != -1 && entry->year != -1)
  609. snprintf(date, sizeof(date), "**/%02d/%04d", entry->day, entry->year);
  610. else if (entry->month != -1 && entry->day == -1 && entry->year != -1)
  611. snprintf(date, sizeof(date), "%02d/**/%04d", entry->month, entry->year);
  612. else if (entry->month != -1 && entry->day != -1 && entry->year == -1)
  613. snprintf(date, sizeof(date), "%02d/%02d/****", entry->month, entry->day);
  614. else if (entry->month != -1 && entry->day == -1 && entry->year == -1)
  615. snprintf(date, sizeof(date), "%02d/**/****", entry->month);
  616. else if (entry->month == -1 && entry->day != -1 && entry->year == -1)
  617. snprintf(date, sizeof(date), "**/%02d/****", entry->day);
  618. else if (entry->month == -1 && entry->day == -1 && entry->year != -1)
  619. snprintf(date, sizeof(date), "**/**/%04d", entry->year);
  620. else
  621. snprintf(date, sizeof(date), "%02d/%02d/%04d", entry->month, entry->day, entry->year);
  622. XtVaSetValues(ui->edit_dialog->time,
  623. XtNvalue, time,
  624. NULL);
  625. XtVaSetValues(ui->edit_dialog->date,
  626. XtNvalue, date,
  627. NULL);
  628. XtVaSetValues(ui->edit_dialog->message,
  629. XtNvalue, entry->message ? entry->message : "",
  630. NULL);
  631. XtVaSetValues(ui->edit_dialog->program,
  632. XtNvalue, entry->program ? entry->program : "",
  633. NULL);
  634. if (strchr(entry->days, '*')) {
  635. XtVaSetValues(ui->edit_dialog->mon, XtNstate, TRUE, NULL);
  636. XtVaSetValues(ui->edit_dialog->tue, XtNstate, TRUE, NULL);
  637. XtVaSetValues(ui->edit_dialog->wed, XtNstate, TRUE, NULL);
  638. XtVaSetValues(ui->edit_dialog->thu, XtNstate, TRUE, NULL);
  639. XtVaSetValues(ui->edit_dialog->fri, XtNstate, TRUE, NULL);
  640. XtVaSetValues(ui->edit_dialog->sat, XtNstate, TRUE, NULL);
  641. XtVaSetValues(ui->edit_dialog->sun, XtNstate, TRUE, NULL);
  642. } else {
  643. XtVaSetValues(ui->edit_dialog->mon, XtNstate, FALSE, NULL);
  644. XtVaSetValues(ui->edit_dialog->tue, XtNstate, FALSE, NULL);
  645. XtVaSetValues(ui->edit_dialog->wed, XtNstate, FALSE, NULL);
  646. XtVaSetValues(ui->edit_dialog->thu, XtNstate, FALSE, NULL);
  647. XtVaSetValues(ui->edit_dialog->fri, XtNstate, FALSE, NULL);
  648. XtVaSetValues(ui->edit_dialog->sat, XtNstate, FALSE, NULL);
  649. XtVaSetValues(ui->edit_dialog->sun, XtNstate, FALSE, NULL);
  650. if (strchr(entry->days, 'm'))
  651. XtVaSetValues(ui->edit_dialog->mon, XtNstate, TRUE, NULL);
  652. if (strchr(entry->days, 't'))
  653. XtVaSetValues(ui->edit_dialog->tue, XtNstate, TRUE, NULL);
  654. if (strchr(entry->days, 'w'))
  655. XtVaSetValues(ui->edit_dialog->wed, XtNstate, TRUE, NULL);
  656. if (strchr(entry->days, 'r'))
  657. XtVaSetValues(ui->edit_dialog->thu, XtNstate, TRUE, NULL);
  658. if (strchr(entry->days, 'f'))
  659. XtVaSetValues(ui->edit_dialog->fri, XtNstate, TRUE, NULL);
  660. if (strchr(entry->days, 's'))
  661. XtVaSetValues(ui->edit_dialog->sat, XtNstate, TRUE, NULL);
  662. if (strchr(entry->days, 'u'))
  663. XtVaSetValues(ui->edit_dialog->sun, XtNstate, TRUE, NULL);
  664. }
  665. /* centre align label */
  666. XtRealizeWidget(ui->edit_dialog->dialog);
  667. XtVaGetValues(ui->edit_dialog->form,
  668. XtNwidth, &pw,
  669. NULL);
  670. XtVaGetValues(ui->edit_dialog->label,
  671. XtNwidth, &w,
  672. XtNheight, &h,
  673. XtNborderWidth, &bw,
  674. NULL);
  675. if (w != pw)
  676. XtResizeWidget(ui->edit_dialog->label, pw, h, bw);
  677. /* put the whole mess onto the screen */
  678. XtPopup(ui->edit_dialog->dialog, XtGrabExclusive);
  679. XMapRaised(XtDisplay(ui->edit_dialog->dialog),
  680. XtWindow(ui->edit_dialog->dialog));
  681. }
  682. void
  683. editok_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  684. {
  685. Interface *ui = (Interface *)client_data;
  686. Boolean toggle_state;
  687. Entry *entry;
  688. char *ptr, *message, *program, days[8], **strings;
  689. int found_time, hh, mm, month, day, year, i;
  690. struct list_node *walker;
  691. /* validate user input - a program or message is required */
  692. message = program = NULL;
  693. if ((ptr = get_text(ui->edit_dialog->message)) && strlen(ptr))
  694. message = ptr;
  695. if ((ptr = get_text(ui->edit_dialog->program)) && strlen(ptr))
  696. program = ptr;
  697. if (message == NULL && program == NULL) {
  698. message_dialog(ui->edit_dialog->dialog, "Please enter a message and/or program",
  699. warning_cb, NULL);
  700. return;
  701. }
  702. /* validate time */
  703. found_time = FALSE;
  704. hh = mm = -1;
  705. if ((ptr = get_text(ui->edit_dialog->time)) && strlen(ptr)) {
  706. if (strcmp(ptr, "**:**") == 0) {
  707. hh = mm = -1;
  708. } else if (sscanf(ptr, "%d:%d", &hh, &mm) == 2) {
  709. found_time = TRUE;
  710. } else if (sscanf(ptr, "%d:**", &hh) == 1) {
  711. found_time = TRUE;
  712. } else if (sscanf(ptr, "**:%d", &mm) == 1) {
  713. found_time = TRUE;
  714. } else {
  715. message_dialog(ui->edit_dialog->dialog, "Please enter a valid time",
  716. warning_cb, NULL);
  717. return;
  718. }
  719. if (found_time && (hh > 23 || hh < -1 || mm > 59 || mm < -1)) {
  720. message_dialog(ui->edit_dialog->dialog, "Please enter a valid time",
  721. warning_cb, NULL);
  722. return;
  723. }
  724. }
  725. /* validate date */
  726. month = day = year = -1;
  727. if ((ptr = get_text(ui->edit_dialog->date)) && strlen(ptr)) {
  728. if (sscanf(ptr, "%d/%d/%d ", &month, &day, &year) == 3) {
  729. /* fully specified date */
  730. } else if (sscanf(ptr, "**/%d/%d", &day, &year) == 2) {
  731. month = -1;
  732. } else if (sscanf(ptr, "%d/**/%d", &month, &year) == 2) {
  733. day = -1;
  734. } else if (sscanf(ptr, "%d/%d/**", &month, &day) == 2) {
  735. year = -1;
  736. } else if (sscanf(ptr, "%d/**/**", &month) == 1) {
  737. day = year = -1;
  738. } else if (sscanf(ptr, "**/%d/**", &day) == 1) {
  739. month = year = -1;
  740. } else if (sscanf(ptr, "**/**/%d", &year) == 1) {
  741. month = day = -1;
  742. } else if (strcmp(ptr, "**/**/****") == 0) {
  743. day = month = year = -1;
  744. } else {
  745. message_dialog(ui->edit_dialog->dialog, "Please enter a valid date",
  746. warning_cb, NULL);
  747. return;
  748. }
  749. if (month > 12 || month < -1 || day > 31 || day < -1 || year > 9999 || year < -1) {
  750. message_dialog(ui->edit_dialog->dialog, "Please enter a valid date",
  751. warning_cb, NULL);
  752. return;
  753. }
  754. }
  755. /* validate days */
  756. i = 0;
  757. XtVaGetValues(ui->edit_dialog->mon, XtNstate, &toggle_state, NULL);
  758. if (toggle_state)
  759. days[i++] = 'm';
  760. XtVaGetValues(ui->edit_dialog->tue, XtNstate, &toggle_state, NULL);
  761. if (toggle_state)
  762. days[i++] = 't';
  763. XtVaGetValues(ui->edit_dialog->wed, XtNstate, &toggle_state, NULL);
  764. if (toggle_state)
  765. days[i++] = 'w';
  766. XtVaGetValues(ui->edit_dialog->thu, XtNstate, &toggle_state, NULL);
  767. if (toggle_state)
  768. days[i++] = 'r';
  769. XtVaGetValues(ui->edit_dialog->fri, XtNstate, &toggle_state, NULL);
  770. if (toggle_state)
  771. days[i++] = 'f';
  772. XtVaGetValues(ui->edit_dialog->sat, XtNstate, &toggle_state, NULL);
  773. if (toggle_state)
  774. days[i++] = 's';
  775. XtVaGetValues(ui->edit_dialog->sun, XtNstate, &toggle_state, NULL);
  776. if (toggle_state)
  777. days[i++] = 'u';
  778. days[i] = '\0';
  779. if (strcmp(days, "mtwrfsu") == 0)
  780. strcpy(days, "*");
  781. #ifdef DEBUG
  782. printf("\nEDITED ENTRY\n");
  783. printf("Time : %02d:%02d\n", hh, mm);
  784. printf("Days : %s\n", strlen(days) ? days : "-");
  785. printf("Date : %02d:%02d:%d\n", month, day, year);
  786. printf("Message : %s\n", message);
  787. printf("Program : %s\n", program);
  788. #endif /* DEBUG */
  789. if (ui->selected_entry == -1) {
  790. entry = calloc(1, sizeof(Entry));
  791. list_add(ui->entries, entry);
  792. } else {
  793. entry = list_get(ui->entries, ui->selected_entry);
  794. if (entry->message)
  795. free(entry->message);
  796. if (entry->program)
  797. free(entry->program);
  798. }
  799. entry->hh = hh;
  800. entry->mm = mm;
  801. entry->month = month;
  802. entry->day = day;
  803. entry->year = year;
  804. strcpy(entry->days, days);
  805. entry->message = message ? strdup(message) : NULL;
  806. entry->program = program ? strdup(program) : NULL;
  807. strings = calloc(sizeof(char *), list_length(ui->entries));
  808. for (i = 0, walker = ui->entries->first; walker; walker = walker->next) {
  809. entry = (Entry *)walker->data;
  810. strings[i] = format_line(entry);
  811. i++;
  812. }
  813. XawListChange(ui->list, strings, i, 0, FALSE);
  814. if (ui->selected_entry == -1)
  815. XawListHighlight(ui->list, list_length(ui->entries) - 1);
  816. ui->entries_changed = TRUE;
  817. XtPopdown(ui->edit_dialog->dialog);
  818. }
  819. void
  820. editcancel_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  821. {
  822. Widget dialog = (Widget)client_data;
  823. XtPopdown(dialog);
  824. }
  825. void
  826. delete_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  827. {
  828. XawListReturnStruct *list_selection;
  829. Interface *ui = (Interface *)client_data;
  830. /* ensure something's selected in the list widget */
  831. list_selection = XawListShowCurrent(ui->list);
  832. ui->selected_entry = list_selection->list_index;
  833. if (ui->selected_entry < 0) {
  834. message_dialog(ui->dialog, "Please select an entry to delete",
  835. warning_cb, NULL);
  836. return;
  837. }
  838. confirm_dialog(ui->dialog, "Are you sure you want to delete this entry?",
  839. deleteyes_cb, deleteno_cb, ui);
  840. }
  841. void
  842. deleteyes_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  843. {
  844. Interface *ui = (Interface *)client_data;
  845. char **strings;
  846. int i;
  847. struct list_node *walker;
  848. Entry *entry;
  849. entry = list_remove(ui->entries, ui->selected_entry);
  850. if (entry->program)
  851. free(entry->program);
  852. if (entry->message)
  853. free(entry->message);
  854. free(entry);
  855. strings = calloc(sizeof(char *), list_length(ui->entries));
  856. for (i = 0, walker = ui->entries->first; walker; walker = walker->next) {
  857. entry = (Entry *)walker->data;
  858. strings[i] = format_line(entry);
  859. i++;
  860. }
  861. XawListChange(ui->list, strings, i, 0, FALSE);
  862. XawListHighlight(ui->list, list_length(ui->entries) - 1);
  863. ui->entries_changed = TRUE;
  864. destroy_dialog(widget);
  865. }
  866. void
  867. deleteno_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  868. {
  869. destroy_dialog(widget);
  870. }
  871. void
  872. close_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  873. {
  874. Interface *ui = (Interface *)client_data;
  875. Entry *entry;
  876. struct list_node *walker;
  877. if (ui->entries_changed)
  878. write_config(ui->entries);
  879. for (walker = ui->entries->first; walker; walker = walker->next) {
  880. entry = (Entry *)walker->data;
  881. if (entry->program)
  882. free(entry->program);
  883. if (entry->message)
  884. free(entry->message);
  885. free(entry);
  886. }
  887. list_free(ui->entries);
  888. exit(0);
  889. }
  890. void
  891. warning_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  892. {
  893. destroy_dialog(widget);
  894. }
  895. void
  896. error_cb(Widget widget, XtPointer client_data, XtPointer call_data)
  897. {
  898. destroy_dialog(widget);
  899. exit(1);
  900. }
  901. char *
  902. get_text(Widget widget)
  903. {
  904. char *str;
  905. if (XtIsSubclass(widget, dialogWidgetClass))
  906. XtVaGetValues(widget, XtNvalue, &str, NULL);
  907. else
  908. str = NULL;
  909. return str;
  910. }