/* pal * * Copyright (C) 2004, Scott Kuhl * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "main.h" #include "output.h" #include "event.h" #include "rl.h" /* This only works when 'number' is between 1 and 10 inclusive */ void pal_add_suffix(gint number, gchar* suffix, gint buf_size) { number = number % 10; switch(number) { case 1: snprintf(suffix, buf_size, "%s", _("1st")); return; case 2: snprintf(suffix, buf_size, "%s", _("2nd")); return; case 3: snprintf(suffix, buf_size, "%s", _("3rd")); return; case 4: snprintf(suffix, buf_size, "%s", _("4th")); return; case 5: snprintf(suffix, buf_size, "%s", _("5th")); return; case 6: snprintf(suffix, buf_size, "%s", _("6th")); return; case 7: snprintf(suffix, buf_size, "%s", _("7th")); return; case 8: snprintf(suffix, buf_size, "%s", _("8th")); return; case 9: snprintf(suffix, buf_size, "%s", _("9th")); return; case 10: snprintf(suffix, buf_size, "%s", _("10th")); return; default: *suffix = '\0'; return; } } gchar* pal_add_get_range() { g_print("\n"); pal_output_fg(BRIGHT, GREEN, "> "); g_print(_("Does this event have starting and ending dates? ")); if(pal_rl_get_y_n(_("[y/n]: "))) { GDate* d1 = NULL; GDate* d2 = NULL; gchar buf[1024]; gchar* s; gboolean bad_range = FALSE; do { /* set back to null for loop to work properly */ d1 = NULL; d2 = NULL; bad_range = FALSE; while(d1 == NULL) { s = pal_rl_get_line(_("Start date: ")); d1 = get_query_date(s, FALSE); g_free(s); } while(d2 == NULL) { s = pal_rl_get_line(_("End date: ")); d2 = get_query_date(s, FALSE); g_free(s); } if(g_date_days_between(d1,d2) < 1) { pal_output_error(_("ERROR: The end date is the same as or before the start date.\n")); d1 = NULL; d2 = NULL; bad_range = TRUE; continue; } g_date_strftime(buf, 1024, "%a %e %b %Y", d1); g_print("%s%s\n", _("Start date: "), buf); g_date_strftime(buf, 1024, "%a %e %b %Y", d2); g_print("%s%s\n", _("End date: "), buf); snprintf(buf, 1024, "%s ", _("Accept? [y/n]:")); } while(bad_range || !pal_rl_get_y_n(buf)); s = g_strconcat(":", get_key(d1), ":", get_key(d2), NULL); g_date_free(d1); g_date_free(d2); return s; } else return g_strdup(""); } /* reuturned string should be freed */ gchar* pal_add_get_recur(GDate* date) { gchar* key; gchar* s; g_print("\n"); pal_output_fg(BRIGHT, GREEN, "> "); g_print(_("Is the event recurring? ")); key = get_key(date); if(pal_rl_get_y_n(_("[y/n]: "))) { gchar* selection; gchar buf[128]; gchar buf2[128]; gchar suffix[16]; gboolean last_weekday = FALSE; pal_output_fg(BRIGHT, GREEN, "> "); g_print(_("Select how often this event occurs\n")); pal_output_attr(BRIGHT, " 1 "); g_print(_("- Daily\n")); pal_output_attr(BRIGHT, " 2 "); g_date_strftime(buf, 128, "%A", date); g_print(_("- Weekly: Every %s\n"), buf); pal_output_attr(BRIGHT, " 3 "); g_print(_("- Monthly: Day %d of every month\n"), g_date_get_day(date)); pal_output_attr(BRIGHT, " 4 "); pal_add_suffix(get_nth_day(date), suffix, 16); g_date_strftime(buf, 128, "%A", date); g_print(_("- Monthly: The %s %s of every month\n"), suffix, buf); pal_output_attr(BRIGHT, " 5 "); g_date_strftime(buf, 128, "%B", date); g_print(_("- Annually: %d %s\n"), g_date_get_day(date), buf); pal_output_attr(BRIGHT, " 6 "); pal_add_suffix(get_nth_day(date), suffix, 16); g_date_strftime(buf, 128, "%A", date); g_date_strftime(buf2, 128, "%B", date); g_print(_("- Annually: The %s %s of every %s\n"), suffix, buf, buf2); if(last_weekday_of_month(date)) { last_weekday = TRUE; pal_output_attr(BRIGHT, " 7 "); g_date_strftime(buf, 128, "%A", date); g_print(_("- Monthly: The last %s of every month\n"), buf); pal_output_attr(BRIGHT, " 8 "); g_date_strftime(buf, 128, "%A", date); g_date_strftime(buf2, 128, "%B", date); g_print(_("- Annually: The last %s in %s\n"), buf, buf2); } g_print("\n"); do { if(last_weekday) selection = pal_rl_get_line(_("Select type [1--8]: ")); else selection = pal_rl_get_line(_("Select type [1--6]: ")); if(g_ascii_strcasecmp(selection, "1") == 0) { snprintf(key, 9, "DAILY"); break; } else if(g_ascii_strcasecmp(selection, "2") == 0) { switch(g_date_get_weekday(date)) { case 1: snprintf(key, 9, "MON"); break; case 2: snprintf(key, 9, "TUE"); break; case 3: snprintf(key, 9, "WED"); break; case 4: snprintf(key, 9, "THU"); break; case 5: snprintf(key, 9, "FRI"); break; case 6: snprintf(key, 9, "SAT"); break; case 7: snprintf(key, 9, "SUN"); break; default: key = NULL; /* impossible...i think */ } break; } else if(g_ascii_strcasecmp(selection, "3") == 0) { key[0] = '0'; key[1] = '0'; key[2] = '0'; key[3] = '0'; key[4] = '0'; key[5] = '0'; break; } else if(g_ascii_strcasecmp(selection, "4") == 0) { int weekday = g_date_get_weekday(date); int n = get_nth_day(date); /* convert weekday to friendly weekday from: 1(mon) -> 7(sun) to: 1(sun) -> 7(sat) */ if(weekday == 7) weekday = 1; else weekday++; snprintf(key, 9, "*00%01d%01d", n, weekday); break; } else if(g_ascii_strcasecmp(selection, "5") == 0) { key[0] = '0'; key[1] = '0'; key[2] = '0'; key[3] = '0'; break; } else if(g_ascii_strcasecmp(selection, "6") == 0) { int weekday = g_date_get_weekday(date); int month = g_date_get_month(date); int n = get_nth_day(date); /* convert weekday to friendly weekday from: 1(mon) -> 7(sun) to: 1(sun) -> 7(sat) */ if(weekday == 7) weekday = 1; else weekday++; snprintf(key, 9, "*%02d%01d%01d", month, n, weekday); break; } else if(g_ascii_strcasecmp(selection, "7") == 0 && last_weekday) { int weekday = g_date_get_weekday(date); /* convert weekday to friendly weekday from: 1(mon) -> 7(sun) to: 1(sun) -> 7(sat) */ if(weekday == 7) weekday = 1; else weekday++; snprintf(key, 9, "*00L%01d", weekday); break; } else if(g_ascii_strcasecmp(selection, "8") == 0 && last_weekday) { int weekday = g_date_get_weekday(date); int month = g_date_get_month(date); /* convert weekday to friendly weekday from: 1(mon) -> 7(sun) to: 1(sun) -> 7(sat) */ if(weekday == 7) weekday = 1; else weekday++; snprintf(key, 9, "*%02dL%01d", month, weekday); break; } }while(1); s = g_strconcat(key, pal_add_get_range(), NULL); return s; } else return get_key(date); } gchar* pal_add_get_desc() { char* desc = NULL; g_print("\n"); pal_output_fg(BRIGHT, GREEN, "> "); g_print(_("What is the description of this event?\n")); do{ if(desc != NULL) { pal_rl_default_text = desc; rl_pre_input_hook = (rl_hook_func_t*) pal_rl_default_text_fn; } desc = pal_rl_get_line(_("Description: ")); rl_pre_input_hook = NULL; } while(!pal_rl_get_y_n(_("Is this description correct? [y/n]: "))); return desc; } /* prompts for a file name */ gchar* pal_add_get_file() { char* filename; gboolean prompt_again = FALSE; pal_output_fg(BRIGHT, GREEN, "> "); g_print(_("Calendar file (usually ending with \".pal\") to add event to:\n")); /* get the filename */ do { prompt_again = FALSE; pal_rl_default_text = g_strconcat(g_get_home_dir(), "/.pal/", NULL); rl_pre_input_hook = (rl_hook_func_t*) pal_rl_default_text_fn; filename = pal_rl_get_line("Filename: "); rl_pre_input_hook = NULL; g_free(pal_rl_default_text); /* replace ~/ or ~ with home dir */ if(*filename == '~') { char* tmp; char* tmp_orig; tmp = g_strconcat(filename, NULL); tmp_orig = tmp; g_free(filename); tmp++; if(*tmp == '/') tmp++; filename = g_strconcat(g_get_home_dir(), "/", tmp, NULL); g_free(tmp_orig); } /* check if file exists */ if(g_file_test(filename, G_FILE_TEST_EXISTS)) { /* make sure it aint a directory */ if(g_file_test(filename, G_FILE_TEST_IS_DIR)) { pal_output_error(_("ERROR: %s is a directory.\n"), filename); prompt_again = TRUE; } } else { /* ask to create the file if it doesn't exist */ pal_output_error(_("WARNING: %s does not exist.\n"), filename); if(!pal_rl_get_y_n(_("Create? [y/n]: "))) prompt_again = TRUE; else { /* create the file */ FILE* file = fopen(filename, "w"); if(file == NULL) { pal_output_error(_("ERROR: Can't create %s.\n"), filename); prompt_again = TRUE; } else { gchar *markers; gchar *event_type; gchar *top_line; g_print("\n"); pal_output_fg(BRIGHT, GREEN, "> "); g_print(_("Information for %s:\n"), filename); do markers = pal_rl_get_line(_("2 character marker for calendar: ")); while(g_utf8_strlen(markers, -1) != 2 || markers[0] == '#'); event_type = pal_rl_get_line(_("Calendar title: ")); top_line = g_strconcat(markers, " ", event_type, "\n", NULL); g_print("\n"); pal_output_fg(BRIGHT, RED, "> "); g_print("%s\n", _("If you want events in this new calendar file to appear when you run pal,\n you need to manually update ~/.pal/pal.conf")); fputs(top_line, file); g_free(top_line); g_free(event_type); g_free(markers); fclose(file); } } } if(prompt_again) g_free(filename); }while (prompt_again); return filename; } void pal_add_write_file(gchar* filename, gchar* key, gchar* desc) { FILE *file = NULL; gchar* write_line = NULL; gboolean no_newline = FALSE; /* check for newline at end of file */ do { file = fopen(filename, "r"); if(file == NULL) { pal_output_error(_("ERROR: Can't read from file %s.\n"), filename); if(!pal_rl_get_y_n(_("Try again? [y/n]: "))) return; } } while(file == NULL); fseek(file, -1, SEEK_END); if(fgetc(file)!= '\n') no_newline = TRUE; fclose(file); /* write the new event out to that file */ do { file = fopen(filename, "a"); if(file == NULL) { pal_output_error(_("ERROR: Can't write to file %s.\n"), filename); if(!pal_rl_get_y_n(_("Try again? [y/n]: "))) return; } } while(file == NULL); /* put a newline at end of file if one isn't there already */ if(no_newline) fputc('\n', file); write_line = g_strconcat(key, " ", desc, "\n", NULL); fputs(write_line, file); g_print("\n"); pal_output_fg(BRIGHT, GREEN, ">>> "); g_print(_("Wrote new event \"%s %s\" to %s.\n"), key, desc, filename); g_free(write_line); fclose(file); } /* Gets a date from the user, then asks if the event is recurring. * This function might return "TODO". */ gchar* pal_add_get_date_recur() { gchar* key; pal_output_fg(BRIGHT, GREEN, "> "); pal_output_wrap(_("Use \"TODO\" to make an event that always occurs on the current date. If the event is recurring, select one of the days the event occurs on."),2,2); key = pal_rl_get_date(); g_print("\n"); if(g_ascii_strcasecmp(key, "TODO") == 0) return key; else return pal_add_get_recur(get_date(key)); } void pal_add_event() { gchar* filename; gchar* description; gchar* key; pal_output_fg(BRIGHT, GREEN, "* * * "); pal_output_attr(BRIGHT, _("Add an event")); pal_output_fg(BRIGHT, GREEN, " * * *\n"); rl_completion_entry_function = rl_filename_completion_function; filename = pal_add_get_file(); g_print("\n"); /* no more completion necessary */ rl_completion_entry_function = (rl_compentry_func_t*) pal_rl_no_match; key = pal_add_get_date_recur(); description = pal_add_get_desc(); if(!is_valid_key(key)) { pal_output_error("INTERNAL ERROR: Please report this error message along with\n"); pal_output_error(" the input that generated it.\n"); pal_output_error("INVALID KEY: %s\n", key); } else pal_add_write_file(filename, key, description); g_free(filename); g_free(description); g_free(key); pal_main_reload(); }