#include "system.h" #include "configure.h" #include "util.h" #include #include #include #include #include #include void lj_config_file(lj_config * config); void lj_set_config(lj_config * config, const char *key, const char *value); void lj_ask_username(lj_config *config); void lj_usage(void) { puts ( "Usage: clive [ -u username ] [ -w password ] [ -j journal ] [ -s subject ]\n" " [ -r security ] [ -f mood ] [ -i userpic ] [ -m music ] [-p] [-d]\n" " [ --backdate YYYMMDDhhmm ] [ --replace itemid ]\n" " [ --charset encoding]\n" " [ --plainpass ] [ --hashpass ] [ --softreturn ]\n" " clive [ --loginonly | --nologin ]\n" " clive [ --lfrgp | --laccess | --lpic | --lfriends | --levents [num] ]\n" " clive [ --addfriend name | --delfriend name ]\n" ); } int lj_init_config(int argc, char **argv, lj_config * config) { int c, optindex; static struct option longopts[] = { {"config", required_argument, 0, 'c'}, {"nocomments", no_argument, 0, 'd'}, {"mood", required_argument, 0, 'f'}, {"userpic", required_argument, 0, 'i'}, {"usejournal", required_argument, 0, 'j'}, {"music", required_argument, 0, 'm'}, {"preformat", no_argument, 0, 'p'}, {"security", required_argument, 0, 'r'}, {"subject", required_argument, 0, 's'}, {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'w'}, {"help", no_argument, 0, '?'}, {"version", no_argument, 0, 'v'}, {"plainpass", no_argument, 0, 1}, /* config->plainpass */ {"hashpass", no_argument, 0, 1}, /* config->hashpass */ {"backdate", required_argument, 0, 0}, /* config->backdated */ {"nologin", no_argument, 0, 1}, /* config->nologin */ {"loginonly", no_argument, 0, 1}, /* config->loginonly */ {"lfrgp", no_argument, 0, 1}, /* config->listfrgp */ {"laccess", no_argument, 0, 1}, /* config->listaccess */ {"lpic", no_argument, 0, 1}, {"lfriends", no_argument, 0, 1}, {"levents", optional_argument, 0, 1}, {"lcomments", optional_argument, 0, 1}, {"replace", required_argument, 0, 1}, {"addfriend", required_argument, 0, 1}, {"delfriend", required_argument, 0, 1}, {"softreturn", no_argument, 0, 1}, {"charset", required_argument, 0, 0}, {NULL, 0, 0, 0}, }; /* When making changes to the above predefined array, * be sure to fix any index changes here */ longopts[13].flag = &(config->plainpass); longopts[14].flag = &(config->hashpass); longopts[16].flag = &(config->nologin); config->nologin = 0; /* we default to logging in */ longopts[17].flag = &(config->loginonly); config->loginonly = 0; /* we default to also posting */ longopts[18].flag = &(config->lfrgp); config->lfrgp = 0; /* normally we 'll post */ longopts[19].flag = &(config->laccess); config->laccess = 0; longopts[20].flag = &(config->lpic); config->lpic = 0; longopts[21].flag = &(config->lfriends); config->lfriends = 0; longopts[22].flag = &(config->levents); config->levents = 0; longopts[23].flag = &(config->lcomments); config->lcomments = 0; longopts[24].flag = &(config->replace); config->replace = 0; longopts[25].flag = &(config->addfriend); config->addfriend = 0; longopts[26].flag = &(config->delfriend); config->delfriend = 0; longopts[27].flag = &(config->softreturn); config->softreturn = 0; config->username = config->password = config->usejournal = config->subject = config->server_host = config->server_path = config->mood = config->userpic = config->editor = config->rcfile = config->customsecurity = config->music = config->charset = NULL; config->plainpass = config->hashpass = config->security = config->allowmask = config->nocomments = config->preformatted = config->backdated = config->server_port = config->getmoods = config->getmenus = config->getpickws = 0; config->dateback[0] = '\0'; lj_debug(3, "Getting command-line parameters"); lj_debug(3, "argc: [%d]\n", argc); /* * when you add options to the array above that have single character * equivalents, be sure to add them to this string here. */ while ((c = getopt_long(argc, (char **)argv, "c:df:i:j:m:pr:s:u:vw:?", longopts, &optindex)) >= 0) { switch (c) { case 0: /* * these are our long options, and so we switch again * when making changes to the predefined array, make * sure to fix the numbers so they match the proper * indexes here */ switch (optindex) { case 15: if (strlen(optarg) == 12) { config->backdated++; lj_strcopy(config->dateback, optarg); } else { lj_error("Invalid date string. " "Date format YYYYMMDDhhmm\n"); } lj_debug(2, "Backdating entry [%s]\n", config->dateback); break; case 20: config->getpickws++; break; case 22: if (optarg) config->levents = atoi(optarg); break; case 23: if (optarg) config->lcomments = atoi(optarg); break; case 24: config->replace = atoi(optarg); break; case 25: case 26: config->editfriend = strdup(optarg); break; case 28: lj_set_config(config, "charset", optarg); break; } break; case 'c': lj_set_config(config, "rcfile", optarg); break; case 'd': config->nocomments++; lj_debug(2, "Comments disabled"); break; case 'f': lj_set_config(config, "mood", optarg); break; case 'i': config->getpickws++; lj_set_config(config, "userpic", optarg); break; case 'j': lj_set_config(config, "usejournal", optarg); break; case 'm': lj_set_config(config, "music", optarg); break; case 'p': config->preformatted++; lj_debug(2, "Preformatted text enabled"); break; case 'r': lj_set_config(config, "security", optarg); break; case 's': lj_set_config(config, "subject", optarg); break; case 'u': lj_set_config(config, "username", optarg); break; case 'v': fprintf(stdout, "POSIX-Clive/%s\n", VERSION); exit(0); case 'w': lj_set_config(config, "password", optarg); break; case '?': lj_usage(); exit(0); } } lj_debug(3, "Got command line options"); /* Here we determine which config file to read from */ if (config->rcfile == NULL) asprintf(&config->rcfile, "%s/.cliverc", getenv("HOME")); /* else we 've already got a config file name so.... */ lj_config_file(config); /* we can do this because lj_set_config checks for NULL */ lj_set_config(config, "editor", getenv("EDITOR")); lj_set_config(config, "editor", getenv("VISUAL")); lj_set_config(config, "server_host", "www.livejournal.com"); lj_set_config(config, "server_path", "/interface/flat"); lj_set_config(config, "charset", "ISO-8859-1"); config->server_port = 80; lj_ask_username(config); return 0; } void lj_set_config(lj_config * config, const char * const key, const char * const value) { if (!key || !value) return; if (!strcmp(key, "username")) { if ((config->username == NULL) || !strcmp(config->username, "")) { config->username = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->username); } } else if (!strcmp(key, "password")) { if ((config->password == NULL) || !strcmp(config->password, "")) { config->password = strdup(value); lj_debug(2, "%s: [******]\n", key); } } else if (!strcmp(key, "usejournal")) { if ((config->usejournal == NULL) || !strcmp(config->usejournal, "")) { config->usejournal = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->usejournal); } } else if (!strcmp(key, "subject")) { if ((config->subject == NULL) || !strcmp(config->subject, "")) { config->subject = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->subject); } } else if (!strcmp(key, "server_host")) { if ((config->server_host == NULL) || !strcmp(config->server_host, "")) { config->server_host = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->server_host); } } else if (!strcmp(key, "server_path")) { if ((config->server_path == NULL) || !strcmp(config->server_path, "")) { config->server_path = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->server_path); } } else if (!strcmp(key, "editor")) { if ((config->editor == NULL) || !strcmp(config->editor, "")) { config->editor = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->editor); } } else if (!strcmp(key, "rcfile")) { if ((config->rcfile == NULL) || !strcmp(config->rcfile, "")) { config->rcfile = strdup(value); lj_debug(2, "%s: [%s]\n", key, config->rcfile); } } else if (!strcmp(key, "security")) { int i = 0; if (value[0] == ':' && ((config->customsecurity == NULL) || !strcmp(config->customsecurity, ""))) { /* custom security */ config->customsecurity = strdup(value); } else if (!strcmp(value, "private")) { /* * do not confuse the number for value with the * number for the security config. That is solely * coincedence. */ config->security = 1; } else if (!strcmp(value, "friends")) { config->security = 2; /* usemask */ config->allowmask = 1; } else if ((i = atoi(optarg))) { char buff[64]; sprintf(buff, "%d", i); if (strlen(buff) == strlen(optarg)) { switch (i) { case 1: /* private */ config->security = 1; break; case 2: /* friends */ config->security = 2; config->allowmask = 1; break; default: lj_error("Invalid security setting. . . exiting\n"); break; } } else lj_error("Invalid security setting. . . exiting\n"); } else lj_error("Invalid security setting. . . exiting\n"); if (config->customsecurity) lj_debug(2, "customsecurity: [%s]\n", config->customsecurity); else lj_debug(2, "security: [%d]\n", config->security); lj_debug(2, "allowmask: [%d]\n", config->allowmask); } else if (!strcmp(key, "mood")) { if ((config->mood == NULL) || !strcmp(config->mood, "")) { config->mood = strdup(value); config->getmoods++; lj_debug(2, "mood: [%s]\n", config->mood); } } else if (!strcmp(key, "getmoods")) { config->getmoods++; } else if (!strcmp(key, "userpic")) { if ((config->userpic == NULL) || !strcmp(config->userpic, "")) { config->userpic = strdup(value); config->getpickws++; lj_debug(2, "userpic: [%s]\n", config->userpic); } } else if (!strcmp(key, "music")) { if ((config->music == NULL) || !strcmp(config->music, "")) { config->music = strdup(value); lj_debug(2, "music: [%s]\n", config->music); } } else if (!strcmp(key, "softreturn")) { if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || (atoi(value) > 0)) { config->softreturn = 1; } } else if (!strcmp(key, "charset")) { if (NULL == config->charset) config->charset = strdup(value); } /* add new option here */ } void lj_config_file(lj_config * config) { FILE *cfile; char buffer[LJ_BUFFER_MAX], key[LJ_BUFFER_MAX], value[LJ_BUFFER_MAX]; int i, j; /* * I should add some better error handling. Right now, if your * config file isn't just perfect...the program will probably blow * up. */ lj_debug(3, "Attempting to open [%s] to read config\n", config->rcfile); if ((cfile = fopen(config->rcfile, "r")) == NULL) return; while (fgets(buffer, LJ_BUFFER_MAX, cfile)) { /* * each buffer should be either whitespace, comments, or * one config item a line must be *either* a comment, * whitespace, or config item cannot mix config and * comment */ chomp(buffer); lj_debug(3, "config [%s]\n", buffer); /*Test for leading '#' for comment */ if (buffer[0] == '#') continue; /* now we slurp up the leading whitespace */ for (i = 0; (buffer[i] == ' ') || (buffer[i] == '\t'); i++) /* DO NOTHING */; /* now we get the key */ for (j = 0; (buffer[i] != ' ') && (buffer[i] != '\t') && (buffer[i] != '='); i++, j++) { key[j] = buffer[i]; } key[j] = '\0'; lj_debug(4, "key [%s]", key); /* * now we slurp up the characters between the key and the * value */ for (; (buffer[i] == ' ') || (buffer[i] == '\t') || (buffer[i] == '='); i++) /* DO NOTHING */; /* * We're going to slurp the entire rest of the buffer then * trim off trailing whitespace */ for (j = 0; i < (int)strlen(buffer); j++, i++) { value[j] = buffer[i]; } for (i = j - 1; i > 0; i--) { if ((value[i] != ' ') && (value[i] != '\t')) break; } value[i + 1] = '\0'; /* terminate our string */ lj_debug(4, " value [%s]\n", value); /* and finally, we use them */ lj_set_config(config, key, value); } } void lj_ask_username(lj_config *config) { if (!config->username) { char name[LJ_BUFFER_MAX]; if (!isatty(fileno(stdin))) lj_error("Won't prompt for username without a tty\n"); printf("Username: "); fgets(name, LJ_BUFFER_MAX, stdin); chomp(name); if (!strlen(name)) lj_error("Won't continue without a username\n"); lj_set_config(config, "username", name); } if (!config->password) { char *pass; if (!isatty(fileno(stdin))) lj_error("Won't prompt for password without a tty\n"); pass = getpass("Password: "); if (!strlen(pass)) lj_error("Won't continue without a password\n"); lj_set_config(config, "password", pass); } }