/********************************************************************\ Name: elogd.c Created by: Stefan Ritt Contents: Web server program for Electronic Logbook ELOG $Log$ Revision 1.330 2004/06/04 14:51:40 midas Implemented stristr Revision 1.329 2004/06/04 14:03:15 midas Fixed stack overflow under Windows on resubmit of entry Revision 1.328 2004/05/21 13:02:51 midas Fixed bug with date attributes and 'subst on edit' Revision 1.327 2004/05/19 20:27:50 midas Added
and
to be recognized as HTML in attributes Revision 1.326 2004/05/18 21:46:08 midas Allow ',' and '.' and '-' for numeric format Revision 1.325 2004/05/11 09:16:03 midas Fixed typo Revision 1.324 2004/05/10 19:46:07 midas Extendable options can now reside also in [globa] section Revision 1.323 2004/05/10 09:34:27 midas Fixed compiler warning Revision 1.322 2004/05/08 15:02:01 midas Fixed bug with remove _all_ leading to infinite page forwarding Revision 1.321 2004/05/05 15:26:04 midas Fixed compiler warning Revision 1.320 2004/05/05 15:24:45 midas Changed redirection to absolute location Revision 1.319 2004/04/30 22:17:29 midas Implemented text body CSV import Revision 1.318 2004/04/08 14:21:14 midas Implemented 'protect selection page' Revision 1.317 2004/04/06 21:19:59 midas Fixed problem with multiple quick filters on attributes without option lists Revision 1.316 2004/03/27 14:33:59 midas Implemeted first version of favicon Revision 1.315 2004/03/26 08:28:29 midas Version 2.5.2 Revision 1.314 2004/03/25 20:33:47 midas *** empty log message *** Revision 1.313 2004/03/25 19:47:48 midas Fixed problem with attributes containing spaces Revision 1.312 2004/03/24 20:44:21 midas Improved synchronization speed Revision 1.311 2004/03/22 21:13:07 midas Improved speed of strieq() Revision 1.310 2004/03/22 14:17:31 midas Implemented 'display ' for single entry display Revision 1.309 2004/03/22 14:14:57 midas Implemented 'display ' Revision 1.308 2004/03/22 10:30:37 midas Added CSV (;) export Revision 1.307 2004/03/21 20:01:48 midas Version 2.5.2 beta Revision 1.306 2004/03/21 19:25:18 midas Implemented XML encoding Revision 1.305 2004/03/21 18:46:31 midas Removed size parameter in csv_import Revision 1.304 2004/03/21 18:42:59 midas Implemented CSV import and XML export Revision 1.303 2004/03/19 15:11:20 midas Implemented 'guest list display' Revision 1.302 2004/03/19 11:12:00 midas Implemented 'extendable options' for MOptions Revision 1.301 2004/03/19 10:30:56 midas Fixed bug with topgroup initialization Revision 1.300 2004/03/17 21:11:04 midas Removed debug print Revision 1.299 2004/03/17 20:57:07 midas Fixed config sync problem due to CRLF-LF Revision 1.298 2004/03/16 15:39:53 midas Fixed endless loop in strip_html Revision 1.297 2004/03/16 08:48:30 midas Fixed format compiler warnings Revision 1.296 2004/03/15 20:07:34 midas Conditional attributes get evaluated correctly during editing of existing entries Revision 1.295 2004/03/15 08:02:46 midas Fixed crashing elogd in threaded display Revision 1.294 2004/03/14 16:43:29 midas Implemented option 'guest display' Revision 1.293 2004/03/13 21:07:58 midas Implemented and between conditions Revision 1.292 2004/03/13 15:00:05 midas Implemented OR's of several conditions Revision 1.291 2004/03/11 11:42:09 midas Change POST action to './' for OS-X IE Revision 1.290 2004/03/10 15:54:03 midas Strip HTML from title bar and summary display Revision 1.289 2004/03/10 14:53:40 midas Fixed bug with MOptions and conditional attributes Revision 1.288 2004/03/09 09:56:04 midas Implemented 'ID display' Revision 1.287 2004/03/08 21:24:43 midas Tried to reduce required stack size in threaded display Revision 1.286 2004/03/08 20:49:18 midas Fixed bug with supressed email notification box and conditional attributes Revision 1.285 2004/03/08 13:00:12 midas Filter entries with invalid date Revision 1.284 2004/03/08 12:52:51 midas Filter entries with invalid date Revision 1.283 2004/03/08 09:41:23 midas Substitutions now also work with 'preset test' Revision 1.282 2004/03/08 08:59:06 midas Evaluage 'pre/append on edit/reply' even for empty entries Revision 1.281 2004/03/08 08:13:09 midas Replaces __TIMESTAMP__ with __DATE__ and __TIME__ Revision 1.280 2004/03/06 11:41:58 midas Made preset $date for date attributes working Revision 1.279 2004/03/05 22:35:15 midas Added Prepend/Append on Edit/Reply Revision 1.278 2004/03/05 21:40:01 midas Substitution of $message id and $entry time now works on all possible places Revision 1.277 2004/03/05 20:39:09 midas Allocate heap memory in display_line Revision 1.276 2004/03/03 10:29:56 midas Fixed bug with date attribute email notification Revision 1.275 2004/03/01 15:56:47 midas Fixed bug with top text Revision 1.274 2004/03/01 07:32:29 midas Added label for 'search across all logbooks' Revision 1.273 2004/02/27 08:20:02 midas Do not sort 'edit' and 'delete' in 'list display' Revision 1.272 2004/02/27 08:10:40 midas Added 'edit' and 'delete' to 'list display' Revision 1.271 2004/02/26 21:06:32 midas Added CSV import page Revision 1.270 2004/02/26 13:41:17 midas Changed strupr() to toupper() Revision 1.269 2004/02/26 13:16:34 midas Show attribute values as HTML if the contain or in listing Revision 1.268 2004/02/26 13:09:14 midas Show attribute values as HTML if the contain or Revision 1.267 2004/02/26 13:00:27 midas Fixed bug with 'start page = 0?cmd=Last Revision 1.266 2004/02/26 12:41:42 midas Fixed bug in el_decode, added ')) { free(str); return TRUE; } if (strstr(str, "
")) { free(str); return TRUE; } if (strstr(str, "
")) { free(str); return TRUE; } free(str); return FALSE; } /*------------------------------------------------------------------*/ void strip_html(char *s) { char *p; while ((p = strchr(s, '<')) != NULL) { if (strchr(p, '>')) strcpy(p, strchr(p, '>') + 1); else *p = 0; } } /*------------------------------------------------------------------*/ void insert_breaks(char *str, int n, int size) { int i, j, i_last; i_last = 0; for (i = 0; i < (int) strlen(str); i++) { if (str[i] == '\r') i_last = i; /* if more than n chars without return, insert one */ if (i - i_last >= n && (int) strlen(str) + 3 < size) { /* find previous blank */ while (i > i_last && str[i] != ' ') i--; if (str[i] == ' ') i++; /* move trailing string one char further */ for (j = strlen(str) + 2; j > i; j--) str[j] = str[j - 2]; /* set CR */ str[i++] = '\r'; str[i++] = '\n'; i_last = i; } } } /*------------------------------------------------------------------*/ void rsputs(const char *str) { if (strlen_retbuf + (int) strlen(str) > return_buffer_size) { return_buffer = realloc(return_buffer, return_buffer_size + 100000); memset(return_buffer + return_buffer_size, 0, 100000); return_buffer_size += 100000; } strcpy(return_buffer + strlen_retbuf, str); strlen_retbuf += strlen(str); } /*------------------------------------------------------------------*/ char *list[] = { "http://", "https://", "ftp://", "mailto:", "elog:", "file://", "" }; void rsputs2(const char *str) { int i, j, k, l, m, n; char *p, *pd, link[1000], link_text[1000], tmp[256]; if (strlen_retbuf + (int) strlen(str) > return_buffer_size) { return_buffer = realloc(return_buffer, return_buffer_size + 100000); memset(return_buffer + return_buffer_size, 0, 100000); return_buffer_size += 100000; } j = strlen_retbuf; for (i = 0; i < (int) strlen(str); i++) { for (l = 0; list[l][0]; l++) { if (strncmp(str + i, list[l], strlen(list[l])) == 0) { p = (char *) (str + i + strlen(list[l])); i += strlen(list[l]); for (k = 0; *p && strcspn(p, " ,;\t\n\r({[)}]"); k++, i++) link[k] = *p++; link[k] = 0; i--; /* link may not end with a '.' (like in a sentence) */ if (link[k - 1] == '.') { link[k - 1] = 0; k--; i--; } /* check if link contains coloring */ p = strchr(link, '\001'); if (p != NULL) { strlcpy(link_text, link, sizeof(link_text)); /* skip everything between '<' and '>' */ pd = p; while (*pd && *pd != '\002') *p = *pd++; strcpy(p, pd + 1); /* skip '' */ p = strchr(link, '\001'); if (p != NULL) { pd = p; while (*pd && *pd != '\002') *p = *pd++; strcpy(p, pd + 1); } /* correct link text */ for (n = 0; n < (int) strlen(link_text); n++) { switch (link_text[n]) { /* the translation for the search highliting */ case '\001': link_text[n] = '<'; break; case '\002': link_text[n] = '>'; break; case '\003': link_text[n] = '\"'; break; case '\004': link_text[n] = ' '; break; } } } else strlcpy(link_text, link, sizeof(link_text)); if (strcmp(list[l], "elog:") == 0) { strlcpy(tmp, link, sizeof(tmp)); if (strchr(tmp, '/')) *strchr(tmp, '/') = 0; for (m = 0; m < (int) strlen(tmp); m++) if (!isdigit(tmp[m])) break; if (m < (int) strlen(tmp)) /* if link contains reference to other logbook, add ".." in front */ sprintf(return_buffer + j, "
elog:%s", link, link_text); else if (link[0] == '/') sprintf(return_buffer + j, "elog:%s", _current_message_id, link, link_text); else sprintf(return_buffer + j, "elog:%s", link, link_text); } else { sprintf(return_buffer + j, "%s", list[l], link, list[l]); j += strlen(return_buffer + j); strlen_retbuf = j; /* link_text can contain special characters */ rsputs2(link_text); j = strlen_retbuf; sprintf(return_buffer + j, ""); } j += strlen(return_buffer + j); break; } } if (!list[l][0]) { if (strncmp(str + i, "
", 4) == 0) { strcpy(return_buffer + j, "
"); j += 4; i += 3; } else switch (str[i]) { case '<': strcat(return_buffer, "<"); j += 4; break; case '>': strcat(return_buffer, ">"); j += 4; break; /* the translation for the search highliting */ case '\001': strcat(return_buffer, "<"); j++; break; case '\002': strcat(return_buffer, ">"); j++; break; case '\003': strcat(return_buffer, "\""); j++; break; case '\004': strcat(return_buffer, " "); j++; break; default: return_buffer[j++] = str[i]; } } } return_buffer[j] = 0; strlen_retbuf = j; } /*------------------------------------------------------------------*/ void rsprintf(const char *format, ...) { va_list argptr; char str[10000]; va_start(argptr, format); vsprintf(str, (char *) format, argptr); va_end(argptr); if (strlen_retbuf + (int) strlen(str) > return_buffer_size) { return_buffer = realloc(return_buffer, return_buffer_size + 100000); memset(return_buffer + return_buffer_size, 0, 100000); return_buffer_size += 100000; } strcpy(return_buffer + strlen_retbuf, str); strlen_retbuf += strlen(str); } /*------------------------------------------------------------------*/ void flush_return_buffer() { send(_sock, return_buffer, strlen_retbuf, 0); memset(return_buffer, 0, return_buffer_size); strlen_retbuf = 0; } /*------------------------------------------------------------------*/ /* Parameter handling functions similar to setenv/getenv */ void initparam() { memset(_param, 0, sizeof(_param)); memset(_value, 0, sizeof(_value)); _mtext[0] = 0; _cmdline[0] = 0; } int setparam(char *param, char *value) { int i; char str[10000]; if (strieq(param, "text")) { if (strlen(value) >= TEXT_SIZE) { sprintf(str, "Error: Entry text too big (%d bytes). Please increase TEXT_SIZE and recompile elogd\n", strlen(value)); show_error(str); return 0; } strlcpy(_mtext, value, TEXT_SIZE); return 1; } if (strieq(param, "cmdline")) { if (strlen(value) >= CMD_SIZE) { sprintf(str, "Error: Command line too big (%d bytes). Please increase CMD_SIZE and recompile elogd\n", strlen(value)); show_error(str); return 0; } strlcpy(_cmdline, value, CMD_SIZE); return 1; } /* paremeters can be superseeded */ for (i = 0; i < MAX_PARAM; i++) if (_param[i][0] == 0 || strieq(param, _param[i])) break; if (i < MAX_PARAM) { if (strlen(param) >= NAME_LENGTH) { sprintf(str, "Error: Parameter name too big (%d bytes).\n", strlen(param)); show_error(str); return 0; } strlcpy(_param[i], param, NAME_LENGTH); if (strlen(value) >= NAME_LENGTH) { sprintf(str, "Error: Parameter value for parameter %s too big (%d bytes). Please increase NAME_LENGTH and recompile elogd\n", param, strlen(value)); show_error(str); return 0; } strlcpy(_value[i], value, NAME_LENGTH); } else { sprintf(str, "Error: Too many parameters (> %d). Cannot perform operation.\n", MAX_PARAM); show_error(str); return 0; } return 1; } char *getparam(char *param) { int i; if (strieq(param, "text")) return _mtext; if (strieq(param, "cmdline")) return _cmdline; for (i = 0; i < MAX_PARAM && _param[i][0]; i++) if (strieq(param, _param[i])) break; if (i < MAX_PARAM) return _value[i]; return NULL; } BOOL enumparam(int n, char *param, char *value) { param[0] = value[0] = 0; if (n >= MAX_PARAM) return FALSE; if (_param[n][0] == 0) return FALSE; strcpy(param, _param[n]); strcpy(value, _value[n]); return TRUE; } BOOL isparam(char *param) { int i; for (i = 0; i < MAX_PARAM && _param[i][0]; i++) if (strieq(param, _param[i])) break; if (i < MAX_PARAM && _param[i][0]) return TRUE; return FALSE; } void unsetparam(char *param) { int i; for (i = 0; i < MAX_PARAM; i++) if (strieq(param, _param[i])) break; if (i < MAX_PARAM) { for (; i < MAX_PARAM - 1; i++) { strlcpy(_param[i], _param[i + 1], NAME_LENGTH); strlcpy(_value[i], _value[i + 1], NAME_LENGTH); } _param[MAX_PARAM - 1][0] = 0; _value[MAX_PARAM - 1][0] = 0; } } /*------------------------------------------------------------------*/ void extract_path(char *str) { char *p, str2[256]; if (strstr(str, "http://")) { p = str + 7; while (*p && *p != '/') p++; if (*p == '/') p++; strcpy(str2, p); strcpy(str, str2); if (str[strlen(str) - 1] == '/') str[strlen(str) - 1] = 0; } } /*------------------------------------------------------------------*/ void set_location(LOGBOOK * lbs, char *rel_path) { char str[NAME_LENGTH]; if (strncmp(rel_path, "http://", 7) == 0) { rsputs("Location: "); rsputs(rel_path); } else { if (lbs) getcfg(lbs->name, "URL", str); else getcfg("global", "URL", str); /* if HTTP request comes from localhost, use localhost as absolute link (needed if running on DSL at home */ if (!str[0] && strstr(http_host, "localhost")) { strcpy(str, "http://localhost"); if (tcp_port != 80) sprintf(str+strlen(str), ":%d", tcp_port); strcat(str, "/"); } if (!str[0]) { /* assemble absolute path from host name and port */ sprintf(str, "http://%s", host_name); if (tcp_port != 80) sprintf(str+strlen(str), ":%d", tcp_port); strcat(str, "/"); } /* add trailing '/' if not present */ if (str[strlen(str) - 1] != '/') strcat(str, "/"); rsputs("Location: "); rsputs(str); /* add top group if existing and not logbook */ if (!lbs && getcfg_topgroup()) { rsputs(getcfg_topgroup()); rsputs("/"); } if (strncmp(rel_path, "../", 3) == 0) rsputs(rel_path + 3); else if (strcmp(rel_path, ".") == 0) { if (lbs) rsputs(lbs->name_enc); } else if (rel_path[0] == '/') rsputs(rel_path + 1); else { if (lbs) { rsputs(lbs->name_enc); rsputs("/"); rsputs(rel_path); } else rsputs(rel_path); } } rsprintf("\r\n\r\nredir\r\n"); } /*------------------------------------------------------------------*/ void set_redir(LOGBOOK * lbs, char *redir) { char str[NAME_LENGTH]; str[0] = 0; /* prepare relative path */ if (redir[0]) strcpy(str, redir); else { if (lbs) sprintf(str, "../%s/", lbs->name_enc); else if (getcfg_topgroup()) sprintf(str, "."); } set_location(lbs, str); } /*------------------------------------------------------------------*/ void set_cookie(LOGBOOK * lbs, char *name, char *value, BOOL global, char *expiration) { char lb_name[256], str[NAME_LENGTH], format[80]; double exp; time_t now; struct tm *gmt; if (lbs) strcpy(lb_name, lbs->name); else strcpy(lb_name, "global"); rsprintf("Set-Cookie: %s=%s;", name, value); /* add path */ if (global) { /* path for all logbooks */ if (getcfg(lb_name, "URL", str)) { extract_path(str); url_encode(str, sizeof(str)); rsprintf(" path=/%s;", str); } else rsprintf(" path=/;"); } else { /* bug in lynx: path has to be absolute */ if (strstr(browser, "Lynx/") != NULL) { /* path for individual logbook */ if (getcfg(lb_name, "URL", str)) { extract_path(str); url_encode(str, sizeof(str)); if (str[0]) rsprintf(" path=/%s/%s;", str, lbs->name_enc); else rsprintf(" path=/%s;", lbs->name_enc); } else rsprintf(" path=/%s;", lbs->name_enc); } } exp = atof(expiration); /* to clear a cookie, set expiration date to yesterday */ if (value[0] == 0) exp = -24; /* add expriation date */ if (exp != 0) { time(&now); now += (int) (3600 * exp); gmt = gmtime(&now); strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT"); strftime(str, sizeof(str), format, gmt); rsprintf(" expires=%s;", str); } rsprintf("\r\n"); } /*------------------------------------------------------------------*/ void redirect(LOGBOOK * lbs, char *rel_path) { /* redirect */ rsprintf("HTTP/1.1 302 Found\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } set_location(lbs, rel_path); } /*------------------------------------------------------------------*/ int strbreak(char *str, char list[][NAME_LENGTH], int size, char *brk) /* break comma-separated list into char array, stripping leading and trailing blanks */ { int i, j; char *p; memset(list, 0, size * NAME_LENGTH); p = str; if (!p || !*p) return 0; while (*p == ' ') p++; for (i = 0; *p && i < size; i++) { if (*p == '"') { p++; j = 0; memset(list[i], 0, NAME_LENGTH); do { /* convert two '"' to one */ if (*p == '"' && *(p + 1) == '"') { list[i][j++] = '"'; p += 2; } else if (*p == '"') { break; } else list[i][j++] = *p++; } while (j < NAME_LENGTH - 1); list[i][j] = 0; /* skip second '"' */ p++; /* skip blanks and break character */ while (*p == ' ') p++; if (*p && strchr(brk, *p)) p++; while (*p == ' ') p++; } else { strlcpy(list[i], p, NAME_LENGTH); for (j = 0; j < (int) strlen(list[i]); j++) if (strchr(brk, list[i][j])) list[i][j] = 0; p += strlen(list[i]); while (*p == ' ') p++; if (*p && strchr(brk, *p)) p++; while (*p == ' ') p++; } while (list[i][strlen(list[i]) - 1] == ' ') list[i][strlen(list[i]) - 1] = 0; if (!*p) break; } if (i == size) return size; return i + 1; } /*------------------------------------------------------------------*/ int scan_attributes(char *logbook) /* scan configuration file for attributes and fill attr_list, attr_options and attr_flags arrays */ { char list[10000], str[NAME_LENGTH], type[NAME_LENGTH], tmp_list[MAX_N_ATTR][NAME_LENGTH]; int i, j, n, m; if (getcfg(logbook, "Attributes", list)) { /* reset attribute flags */ memset(attr_flags, 0, sizeof(attr_flags)); /* get attribute list */ memset(attr_list, 0, sizeof(attr_list)); n = strbreak(list, attr_list, MAX_N_ATTR, ","); /* get options lists for attributes */ memset(attr_options, 0, sizeof(attr_options)); for (i = 0; i < n; i++) { sprintf(str, "Options %s", attr_list[i]); if (getcfg(logbook, str, list)) strbreak(list, attr_options[i], MAX_N_LIST, ","); sprintf(str, "MOptions %s", attr_list[i]); if (getcfg(logbook, str, list)) { strbreak(list, attr_options[i], MAX_N_LIST, ","); attr_flags[i] |= AF_MULTI; } sprintf(str, "ROptions %s", attr_list[i]); if (getcfg(logbook, str, list)) { strbreak(list, attr_options[i], MAX_N_LIST, ","); attr_flags[i] |= AF_RADIO; } sprintf(str, "IOptions %s", attr_list[i]); if (getcfg(logbook, str, list)) { strbreak(list, attr_options[i], MAX_N_LIST, ","); attr_flags[i] |= AF_ICON; } } /* check if attribute required */ getcfg(logbook, "Required Attributes", list); m = strbreak(list, tmp_list, MAX_N_ATTR, ","); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) if (strieq(attr_list[j], tmp_list[i])) attr_flags[j] |= AF_REQUIRED; } /* check if locked attribute */ getcfg(logbook, "Locked Attributes", list); m = strbreak(list, tmp_list, MAX_N_ATTR, ","); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) if (strieq(attr_list[j], tmp_list[i])) attr_flags[j] |= AF_LOCKED; } /* check if fixed attribute for Edit */ getcfg(logbook, "Fixed Attributes Edit", list); m = strbreak(list, tmp_list, MAX_N_ATTR, ","); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) if (strieq(attr_list[j], tmp_list[i])) attr_flags[j] |= AF_FIXED_EDIT; } /* check if fixed attribute for Reply */ getcfg(logbook, "Fixed Attributes Reply", list); m = strbreak(list, tmp_list, MAX_N_ATTR, ","); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) if (strieq(attr_list[j], tmp_list[i])) attr_flags[j] |= AF_FIXED_REPLY; } /* check for extendable options */ getcfg(logbook, "Extendable Options", list); m = strbreak(list, tmp_list, MAX_N_ATTR, ","); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) if (strieq(attr_list[j], tmp_list[i])) attr_flags[j] |= AF_EXTENDABLE; } for (i = 0; i < n; i++) { sprintf(str, "Type %s", attr_list[i]); if (getcfg(logbook, str, type)) { if (strieq(type, "date")) attr_flags[i] |= AF_DATE; if (strieq(type, "numeric")) attr_flags[i] |= AF_NUMERIC; } } } else { memcpy(attr_list, attr_list_default, sizeof(attr_list_default)); memcpy(attr_options, attr_options_default, sizeof(attr_options_default)); memcpy(attr_flags, attr_flags_default, sizeof(attr_flags_default)); n = 4; } return n; } /*------------------------------------------------------------------*/ void show_http_header(BOOL expires) { char str[256]; rsprintf("HTTP/1.1 200 Document follows\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); if (getcfg("global", "charset", str)) rsprintf("Content-Type: text/html;charset=%s\r\n", str); else rsprintf("Content-Type: text/html;charset=iso-8859-1\r\n"); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } if (expires) { rsprintf("Pragma: no-cache\r\n"); rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n"); } rsprintf("\r\n"); } void show_plain_header(int size, char *file_name) { /* header */ rsprintf("HTTP/1.1 200 Document follows\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); rsprintf("Accept-Ranges: bytes\r\n"); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } rsprintf("Pragma: no-cache\r\n"); rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n"); rsprintf("Content-Type: text/plain\r\n"); rsprintf("Content-disposition: attachment; filename=\"%s\"\r\n", file_name); if (size) rsprintf("Content-Length: %d\r\n", size); rsprintf("\r\n"); } void show_html_header(LOGBOOK * lbs, BOOL expires, char *title, BOOL close_head) { char css[256], str[256]; show_http_header(expires); /* DOCTYPE */ rsprintf("\n"); /* page title */ rsprintf("%s\n", title); /* Cascading Style Sheet */ strlcpy(css, "default.css", sizeof(css)); if (lbs != NULL && getcfg(lbs->name, "CSS", str)) strlcpy(css, str, sizeof(css)); else if (lbs == NULL && getcfg("global", "CSS", str)) strlcpy(css, str, sizeof(css)); rsprintf("\n", css); rsprintf("\n"); rsprintf("\n"); if (close_head) rsprintf("\n"); } void show_standard_header(LOGBOOK * lbs, BOOL expires, char *title, char *path) { show_html_header(lbs, expires, title, TRUE); rsprintf("\n"); show_top_text(lbs); if (path) rsprintf("
\n\n", path); else rsprintf("\n\n"); } /*------------------------------------------------------------------*/ void show_upgrade_page(LOGBOOK * lbs) { char str[1000]; show_html_header(lbs, FALSE, "ELOG Upgrade Information", TRUE); rsprintf("\n"); rsprintf("\n\n"); rsprintf ("\n"); rsprintf("
ELog Electronic Logbook Upgrade Information

\n"); rsprintf ("You probably use an elogd.cfg configuration file for a ELOG version\n"); rsprintf ("1.1.x, since it contains a \"Types = ...\" entry. From version\n"); rsprintf("1.2.0 on, the fixed attributes Type and Category have been\n"); rsprintf ("replaced by arbitrary attributes. Please replace these two lines with the\n"); rsprintf("following entries:

\n"); rsprintf("

\n");
   rsprintf("Attributes = Author, Type, Category, Subject\n");
   rsprintf("Required Attributes = Author\n");
   getcfg(lbs->name, "Types", str);
   rsprintf("Options Type = %s\n", str);
   getcfg(lbs->name, "Categories", str);
   rsprintf("Options Category = %s\n", str);
   rsprintf("Page title = $subject\n");
   rsprintf("
\n"); rsprintf("

\n"); rsprintf ("It is of course possible to change the attributes or add new ones. The new\n"); rsprintf("options in the configuration file are described under http://midas.psi.ch/elog/config.html\n"); rsprintf(".\n"); rsprintf("

\n\n"); rsprintf("
\n"); rsprintf("
\n"); rsprintf("S. Ritt, 18 October 2001"); rsprintf("
"); show_bottom_text(lbs); rsprintf("\r\n"); } /*------------------------------------------------------------------*/ LBLIST get_logbook_hierarchy(void) { int i, j, k, n, m, flag; char str[1000], grpname[256], grpmembers[1000]; LBLIST root; char grplist[MAX_N_LIST][NAME_LENGTH]; /* allocate root node */ root = malloc(sizeof(LBNODE)); memset(root, 0, sizeof(LBNODE)); /* enumerate groups */ for (i = n = 0;; i++) { if (!enumcfg("global", grpname, grpmembers, i)) break; flag = 0; strlcpy(str, grpname, sizeof(str)); str[9] = 0; if (strieq(str, "top group")) flag = 2; str[5] = 0; if (strieq(str, "group")) flag = 1; if (flag) { /* allocate new node, increase member pointer array by one */ if (n == 0) root->member = malloc(sizeof(void *)); else root->member = realloc(root->member, (n + 1) * sizeof(void *)); root->member[n] = malloc(sizeof(LBNODE)); if (strlen(grpname) < 7) strlcpy(root->member[n]->name, "Invalid group definition!", 256); else if (flag == 1) strlcpy(root->member[n]->name, grpname + 6, 256); else strlcpy(root->member[n]->name, grpname + 10, 256); m = strbreak(grpmembers, grplist, MAX_N_LIST, ","); root->member[n]->n_members = m; root->member[n]->member = calloc(sizeof(void *), m); root->member[n]->n_members = m; for (j = 0; j < m; j++) { root->member[n]->member[j] = calloc(sizeof(LBNODE), 1); strlcpy(root->member[n]->member[j]->name, grplist[j], 256); } root->member[n]->is_top = (flag == 2); n++; } } root->n_members = n; /* populate nodes with logbooks or other groups */ for (i = 0; i < root->n_members; i++) if (root->member[i]) { for (j = 0; j < root->member[i]->n_members; j++) { /* check if node is valid logbook */ for (k = 0; lb_list[k].name[0]; k++) if (strieq(root->member[i]->member[j]->name, lb_list[k].name)) break; /* check if node is subgroup of other node */ if (!lb_list[k].name[0]) { for (k = 0; k < root->n_members; k++) if (strieq(root->member[i]->member[j]->name, root->member[k]->name)) { /* node is allocated twice, so free one... */ free(root->member[i]->member[j]); /* ... and reference the other */ root->member[i]->member[j] = root->member[k]; /* mark original pointer invalid */ root->member[k] = NULL; break; } } } } /* remove empty slots */ for (i = 0; i < root->n_members; i++) if (root->member[i] == NULL) { for (j = i + 1; j < root->n_members; j++) if (root->member[j]) break; if (j < root->n_members && root->member[j]) { root->member[i] = root->member[j]; root->member[j] = NULL; } } for (i = 0; i < root->n_members; i++) if (root->member[i] == NULL) break; if (i < root->n_members) root->n_members = i; if (n == 0) { for (n = 0; lb_list[n].name[0]; n++); /* make simple list with logbooks */ root->member = calloc(n, sizeof(void *)); root->n_members = n; for (i = 0; i < n; i++) { root->member[i] = calloc(1, sizeof(LBNODE)); strlcpy(root->member[i]->name, lb_list[i].name, 256); } } return root; } /*------------------------------------------------------------------*/ void free_logbook_hierarchy(LBLIST root) { int i; for (i = 0; i < root->n_members; i++) { if (root->member[i]) { free_logbook_hierarchy(root->member[i]); root->member[i] = NULL; } } free(root->member); free(root); } /*------------------------------------------------------------------*/ int is_logbook_in_group(LBLIST pgrp, char *logbook) /* test if "logbook" is in group node plb */ { int i; if (strieq(pgrp->name, logbook)) return 1; for (i = 0; i < pgrp->n_members; i++) { if (strieq(logbook, pgrp->member[i]->name)) return 1; if (pgrp->member[i]->n_members > 0 && is_logbook_in_group(pgrp->member[i], logbook)) return 1; } return 0; } /*------------------------------------------------------------------*/ void show_standard_title(char *logbook, char *text, int printable) { char str[256], ref[256], sclass[32]; int i, j, level; LBLIST phier, pnode, pnext, flb; if (printable) rsprintf ("\n\n"); else rsprintf ("
\n\n"); /* scan logbook hierarchy */ phier = get_logbook_hierarchy(); /*---- logbook selection row ----*/ pnode = phier; /* start at root of tree */ pnext = NULL; if (!printable && getcfg(logbook, "logbook tabs", str) && atoi(str) == 1) { for (level = 0;; level++) { rsprintf("\n\n"); pnode = pnext; pnext = NULL; if (pnode == NULL) break; } } free_logbook_hierarchy(phier); /*---- title row ----*/ rsprintf("\n\n"); } /*------------------------------------------------------------------*/ void show_top_text(LOGBOOK * lbs) { char str[NAME_LENGTH]; int size; if (getcfg(lbs->name, "top text", str)) { FILE *f; char file_name[256], *buf; /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } f = fopen(file_name, "rb"); if (f != NULL) { fseek(f, 0, SEEK_END); size = TELL(fileno(f)); fseek(f, 0, SEEK_SET); buf = malloc(size + 1); fread(buf, 1, size, f); buf[size] = 0; fclose(f); rsputs(buf); } else rsputs(str); } } /*------------------------------------------------------------------*/ void show_bottom_text(LOGBOOK * lbs) { char str[NAME_LENGTH]; int size; if (getcfg(lbs->name, "bottom text", str)) { FILE *f; char file_name[256], *buf; /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } f = fopen(file_name, "rb"); if (f != NULL) { fseek(f, 0, SEEK_END); size = TELL(fileno(f)); fseek(f, 0, SEEK_SET); buf = malloc(size + 1); fread(buf, 1, size, f); buf[size] = 0; fclose(f); rsputs(buf); } else rsputs(str); } else /* add little logo */ rsprintf ("
ELOG V%s
", VERSION); } /*------------------------------------------------------------------*/ void show_error(char *error) { /* header */ show_html_header(NULL, FALSE, "ELOG error", TRUE); rsprintf("
\n"); rsprintf("
\n"); if (level == 0 && getcfg("global", "main tab", str) && !getcfg_topgroup()) rsprintf("%s\n", str); if (level == 1 && getcfg("global", "main tab", str) && getcfg_topgroup()) rsprintf("%s\n", getcfg_topgroup(), str); /* iterate through members of this group */ for (i = 0; i < pnode->n_members; i++) { if (getcfg(pnode->member[i]->name, "Hidden", str) && atoi(str) == 1) continue; strlcpy(str, pnode->member[i]->name, sizeof(str)); /* build reference to first logbook in group */ if (pnode->member[i]->member == NULL) strlcpy(ref, str, sizeof(ref)); // current node is logbook else { flb = pnode->member[i]->member[0]; // current node is group while (flb->member) // so traverse hierarchy flb = flb->member[0]; strlcpy(ref, flb->name, sizeof(ref)); } url_encode(ref, sizeof(ref)); if (is_logbook_in_group(pnode->member[i], logbook)) { /* remember member list of this group for next row */ pnext = pnode->member[i]; if (pnode->member[i]->member == NULL) /* selected logbook */ strcpy(sclass, "sltab"); else /* selected group */ strcpy(sclass, "sgtab"); } else { if (pnode->member[i]->member == NULL) /* unselected logbook */ strcpy(sclass, "ltab"); else /* unselected group */ strcpy(sclass, "gtab"); } if (!pnode->member[i]->is_top) { rsprintf("", sclass, ref); strlcpy(str, pnode->member[i]->name, sizeof(str)); for (j = 0; j < (int) strlen(str); j++) if (str[j] == ' ') rsprintf(" "); else rsprintf("%c", str[j]); rsprintf("\n"); } } rsprintf("
\n"); /* left cell */ rsprintf("\n", str, text); /* middle cell */ if (*getparam("full_name")) rsprintf("\n", loc("Logged in as"), getparam("full_name")); else if (getcfg(logbook, "Guest menu commands", str)) rsprintf("\n", loc("Not logged in")); /* right cell */ rsprintf("\n"); rsprintf("
"); /* use comment as title if available, else logbook name */ if (!getcfg(logbook, "Comment", str)) strcpy(str, logbook); rsprintf("  %s%s %s \"%s\"%s"); if (getcfg(logbook, "Title image URL", str)) rsprintf("\n", str); if (getcfg(logbook, "Title image", str)) rsprintf(str); else rsprintf("\"ELOG"); if (getcfg(logbook, "Title image URL", str)) rsprintf("\n"); rsprintf("
\n", error); rsprintf("\n
%s
"); /* rsprintf("\n"); rsprintf("\n"); */ rsprintf("
\n"); rsprintf("\n"); } /*------------------------------------------------------------------*/ void set_login_cookies(LOGBOOK * lbs, char *user, char *enc_pwd) { char str[256], lb_name[256], exp[80]; BOOL global; rsprintf("HTTP/1.1 302 Found\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } if (lbs) strcpy(lb_name, lbs->name); else strcpy(lb_name, "global"); /* get optional expriation from configuration file */ if (isparam("remember")) { if (!getcfg(lb_name, "Login expiration", exp)) strcpy(exp, "31*24"); /* one month by default */ } else exp[0] = 0; /* check if cookies should be global */ global = getcfg("global", "Password file", str); /* two cookies for password and user name */ set_cookie(lbs, "unm", user, global, exp); set_cookie(lbs, "upwd", enc_pwd, global, exp); set_redir(lbs, getparam("redir")); } /*------------------------------------------------------------------*/ int exist_file(char *file_name) { int fh; fh = open(file_name, O_RDONLY | O_BINARY); if (fh > 0) { close(fh); return 1; } return 0; } /*------------------------------------------------------------------*/ void send_file_direct(char *file_name) { int fh, i, length, delta; char str[MAX_PATH_LENGTH], charset[80], format[80]; time_t now; struct tm *gmt; fh = open(file_name, O_RDONLY | O_BINARY); if (fh > 0) { lseek(fh, 0, SEEK_END); length = TELL(fh); lseek(fh, 0, SEEK_SET); rsprintf("HTTP/1.1 200 Document follows\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); rsprintf("Accept-Ranges: bytes\r\n"); /* set expiration time to one day */ time(&now); now += (int) (3600 * 24); gmt = gmtime(&now); strcpy(format, "%A, %d-%b-%y %H:%M:%S GMT"); strftime(str, sizeof(str), format, gmt); rsprintf("Expires: %s\r\n", str); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } /* return proper header for file type */ for (i = 0; i < (int) strlen(file_name); i++) str[i] = toupper(file_name[i]); str[i] = 0; for (i = 0; filetype[i].ext[0]; i++) if (strstr(str, filetype[i].ext)) break; if (!getcfg("global", "charset", charset)) strcpy(charset, "iso-8859-1"); if (filetype[i].ext[0]) rsprintf("Content-Type: %s;charset=%s\r\n", filetype[i].type, charset); else if (strchr(str, '.') == NULL) rsprintf("Content-Type: text/plain;charset=%s\r\n", charset); else rsprintf("Content-Type: application/octet-stream;charset=%s\r\n", charset); rsprintf("Content-Length: %d\r\n\r\n", length); /* increase return buffer size if file too big */ if (length > return_buffer_size - (int) strlen(return_buffer)) { delta = length - (return_buffer_size - strlen(return_buffer)) + 1000; return_buffer = realloc(return_buffer, return_buffer_size + delta); memset(return_buffer + return_buffer_size, 0, delta); return_buffer_size += delta; } return_length = strlen(return_buffer) + length; read(fh, return_buffer + strlen(return_buffer), length); close(fh); } else { show_html_header(NULL, FALSE, "404 Not Found", TRUE); rsprintf("

Not Found

\r\n"); rsprintf("The requested file %s was not found on this server

\r\n", file_name); rsprintf("


ELOG version %s
\r\n\r\n", VERSION); return_length = strlen_retbuf; keep_alive = 0; } } /*------------------------------------------------------------------*/ void strencode(char *text) { int i; for (i = 0; i < (int) strlen(text); i++) { switch (text[i]) { case '\n': rsprintf("
\n"); break; case '<': rsprintf("<"); break; case '>': rsprintf(">"); break; case '&': rsprintf("&"); break; case '\"': rsprintf("""); break; case ' ': rsprintf(" "); break; /* the translation for the search highliting */ case '\001': rsprintf("<"); break; case '\002': rsprintf(">"); break; case '\003': rsprintf("\""); break; case '\004': rsprintf(" "); break; default: rsprintf("%c", text[i]); } } } /*------------------------------------------------------------------*/ void xmlencode(char *text) { int i; for (i = 0; i < (int) strlen(text); i++) { switch (text[i]) { case '<': rsprintf("<"); break; case '>': rsprintf(">"); break; case '&': rsprintf("&"); break; case '\"': rsprintf("""); break; default: rsprintf("%c", text[i]); } } } /*------------------------------------------------------------------*/ void strencode2(char *b, char *text) { int i; *b = 0; for (i = 0; i < (int) strlen(text); i++) { switch (text[i]) { case '\n': strcat(b, "
\n"); break; case '<': strcat(b, "<"); break; case '>': strcat(b, ">"); break; case '&': strcat(b, "&"); break; case '\"': strcat(b, """); break; default: sprintf(b + strlen(b), "%c", text[i]); } } } /*------------------------------------------------------------------*/ int build_subst_list(LOGBOOK * lbs, char list[][NAME_LENGTH], char value[][NAME_LENGTH], char attrib[][NAME_LENGTH], BOOL format_date) { int i; char str[NAME_LENGTH], format[256]; time_t now; struct tm *ts; /* copy attribute list */ i = 0; if (attrib != NULL) for (; i < lbs->n_attr; i++) { strcpy(list[i], attr_list[i]); if (attrib) strcpy(value[i], attrib[i]); else strcpy(value[i], getparam(attr_list[i])); } /* add remote host */ strcpy(list[i], "remote_host"); strlcpy(value[i++], rem_host, NAME_LENGTH); /* add local host */ strcpy(list[i], "host"); strlcpy(value[i++], host_name, NAME_LENGTH); /* add user names */ strcpy(list[i], "short_name"); strlcpy(value[i++], getparam("unm"), NAME_LENGTH); strcpy(list[i], "long_name"); strlcpy(value[i++], getparam("full_name"), NAME_LENGTH); /* add email */ strcpy(list[i], "user_email"); strcpy(value[i], "mailto:"); strlcat(value[i++], getparam("user_email"), NAME_LENGTH); /* add logbook */ strcpy(list[i], "logbook"); strlcpy(value[i++], lbs->name, NAME_LENGTH); /* add date */ strcpy(list[i], "date"); time(&now); if (format_date) { ts = localtime(&now); if (!getcfg(lbs->name, "Time format", format)) strcpy(format, DEFAULT_TIME_FORMAT); strftime(str, sizeof(str), format, ts); } else sprintf(str, "%d", (int) now); strcpy(value[i++], str); return i; } /*------------------------------------------------------------------*/ void add_subst_list(char list[][NAME_LENGTH], char value[][NAME_LENGTH], char *item, char *str, int *i) { strcpy(list[*i], item); strcpy(value[(*i)++], str); } void add_subst_time(LOGBOOK * lbs, char list[][NAME_LENGTH], char value[][NAME_LENGTH], char *item, char *date, int *i) { char format[80], str[256]; time_t ltime; struct tm *pts; if (!getcfg(lbs->name, "Time format", format)) strcpy(format, DEFAULT_TIME_FORMAT); ltime = date_to_ltime(date); pts = localtime(<ime); strftime(str, sizeof(str), format, pts); add_subst_list(list, value, item, str, i); } /*------------------------------------------------------------------*/ BOOL change_pwd(LOGBOOK * lbs, char *user, char *pwd) { char str[256], file_name[256], line[256], *p, *pl; char *buf; int i, fh, size; getcfg(lbs->name, "Password file", str); if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } fh = open(file_name, O_RDWR | O_BINARY, 644); if (fh > 0) { lseek(fh, 0, SEEK_END); size = TELL(fh); lseek(fh, 0, SEEK_SET); buf = malloc(size + 1); read(fh, buf, size); buf[size] = 0; pl = buf; while (pl < buf + size) { for (i = 0; pl[i] && pl[i] != '\r' && pl[i] != '\n'; i++) line[i] = pl[i]; line[i] = 0; if (line[0] == ';' || line[0] == '#' || line[0] == 0) { pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; continue; } strcpy(str, line); if (strchr(str, ':')) *strchr(str, ':') = 0; if (strcmp(str, user) == 0) break; pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; } /* return if not found */ if (pl >= buf + size) { free(buf); close(fh); return FALSE; } p = strchr(line, ':'); if (p) p = strchr(p + 1, ':'); if (p == NULL) return FALSE; /* replace password */ lseek(fh, 0, SEEK_SET); write(fh, buf, pl - buf); sprintf(str, "%s:%s%s\n", user, pwd, p); write(fh, str, strlen(str)); pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; write(fh, pl, strlen(pl)); #ifdef _MSC_VER chsize(fh, TELL(fh)); #else ftruncate(fh, TELL(fh)); #endif free(buf); close(fh); return TRUE; } return FALSE; } /*------------------------------------------------------------------*/ void show_change_pwd_page(LOGBOOK * lbs) { char str[256], old_pwd[32], new_pwd[32], new_pwd2[32], act_pwd[32], user[80]; int wrong_pwd; do_crypt(getparam("oldpwd"), old_pwd); do_crypt(getparam("newpwd"), new_pwd); do_crypt(getparam("newpwd2"), new_pwd2); strcpy(user, getparam("unm")); if (isparam("config")) strcpy(user, getparam("config")); wrong_pwd = FALSE; if (old_pwd[0] || new_pwd[0]) { if (user[0] && get_user_line(lbs->name, user, act_pwd, NULL, NULL, NULL)) { /* administrator does not have to supply old password */ if (getcfg(lbs->name, "Admin user", str) && strstr(str, getparam("unm")) != 0) wrong_pwd = 0; else { if (strcmp(old_pwd, act_pwd) != 0) wrong_pwd = 1; } if (strcmp(new_pwd, new_pwd2) != 0) wrong_pwd = 2; } /* replace password */ if (!wrong_pwd) change_pwd(lbs, user, new_pwd); if (!wrong_pwd && strcmp(user, getparam("unm")) == 0) { set_login_cookies(lbs, user, new_pwd); return; } if (!wrong_pwd) { /* redirect back to configuration page */ sprintf(str, "?cmd=%s&cfg_user=%s", loc("Config"), getparam("config")); redirect(lbs, str); return; } } show_standard_header(lbs, TRUE, loc("ELOG change password"), NULL); rsprintf(""); if (wrong_pwd == 1) rsprintf("\n", loc("Wrong password")); if (wrong_pwd == 2) rsprintf("\n", loc("New passwords do not match, please retype")); rsprintf("\n", loc("Change password for user"), user); if (!getcfg(lbs->name, "Admin user", str) || !strstr(str, getparam("unm")) != 0) { if (isparam("old_pwd")) rsprintf("\n"); } } rsprintf("\n", loc("New password")); rsprintf ("\n"); rsprintf("\n", loc("Retype new password")); rsprintf ("\n"); rsprintf ("", loc("Submit")); rsprintf("
%s!
%s!
\n"); rsprintf("", user); rsprintf("%s \"%s\"
%s:\n", loc("Old password")); rsprintf("\n"); rsprintf("
%s:
%s:
\n"); show_bottom_text(lbs); rsprintf("
\r\n"); } /*------------------------------------------------------------------*/ int get_last_index(LOGBOOK * lbs, int index) /* return value of specific attribute of last entry, can be used to auto-increment tags */ { int i, message_id; char str[80], attrib[MAX_N_ATTR][NAME_LENGTH], att[MAX_ATTACHMENTS][256]; str[0] = 0; message_id = el_search_message(lbs, EL_LAST, 0, FALSE); if (!message_id) return 0; el_retrieve(lbs, message_id, NULL, attr_list, attrib, lbs->n_attr, NULL, 0, NULL, NULL, att, NULL, NULL); strcpy(str, attrib[index]); /* look for first digit, return value */ for (i = 0; i < (int) strlen(str); i++) if (isdigit(str[i])) break; return atoi(str + i); } /*------------------------------------------------------------------*/ BOOL is_author(LOGBOOK * lbs, char attrib[MAX_N_ATTR][NAME_LENGTH], char *owner) { char str[1000], preset[1000]; int i; /* check if current user is admin */ if (getcfg(lbs->name, "Admin user", str) && strstr(str, getparam("unm")) != 0) return TRUE; /* search attribute which contains short_name of author */ for (i = 0; i < lbs->n_attr; i++) { sprintf(str, "Preset %s", attr_list[i]); if (getcfg(lbs->name, str, preset)) { if (strstr(preset, "$short_name")) { if (strstr(attrib[i], getparam("unm")) == NULL) { strcpy(owner, attrib[i]); return FALSE; } else break; } } } if (i == lbs->n_attr) { /* if not found, search attribute which contains full_name of author */ for (i = 0; i < lbs->n_attr; i++) { sprintf(str, "Preset %s", attr_list[i]); if (getcfg(lbs->name, str, preset)) { if (strstr(preset, "$long_name")) { if (strstr(attrib[i], getparam("full_name")) == NULL) { strcpy(owner, attrib[i]); return FALSE; } } } } } return TRUE; } /*------------------------------------------------------------------*/ BOOL is_cond_attr(int index) { int i; for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) if (strchr(attr_options[index][i], '{') && strchr(attr_options[index][i], '}')) return TRUE; return FALSE; } /*------------------------------------------------------------------*/ void show_date_selector(int day, int month, int year, char *index) { int i; rsprintf("\n"); rsprintf("\n"); if (year) rsprintf (" %s: ", loc("Year"), index, year); else rsprintf(" %s: ", loc("Year"), index); rsprintf("\n\n"); } /*------------------------------------------------------------------*/ void show_edit_form(LOGBOOK * lbs, int message_id, BOOL breply, BOOL bedit, BOOL bupload, BOOL breedit) { int i, j, n, index, size, width, height, fh, length, first, input_size, input_maxlen, format_flags, year, month, day; char str[1000], preset[1000], *p, *pend, star[80], comment[10000], reply_string[256], list[MAX_N_ATTR][NAME_LENGTH], file_name[256], *buffer, format[256], date[80], attrib[MAX_N_ATTR][NAME_LENGTH], *text, orig_tag[80], reply_tag[MAX_REPLY_TO * 10], att[MAX_ATTACHMENTS][256], encoding[80], slist[MAX_N_ATTR + 10][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH], owner[256], locked_by[256], class_value[80], class_name[80], condition[256], ua[NAME_LENGTH], mid[80]; time_t now, ltime; char fl[8][NAME_LENGTH]; struct tm *pts, ts; for (i = 0; i < MAX_ATTACHMENTS; i++) att[i][0] = 0; for (i = 0; i < lbs->n_attr; i++) attrib[i][0] = 0; text = malloc(TEXT_SIZE); text[0] = 0; if (breedit || bupload) { /* get date from parameter */ if (*getparam("entry_date")) strcpy(date, getparam("entry_date")); /* get attributes from parameters */ for (i = 0; i < lbs->n_attr; i++) { strcpy(ua, attr_list[i]); btou(ua); if (attr_flags[i] & AF_MULTI) { attrib[i][0] = 0; first = 1; for (j = 0; j < MAX_N_LIST; j++) { sprintf(str, "%s_%d", ua, j); if (getparam(str)) { if (*getparam(str)) { if (first) first = 0; else strlcat(attrib[i], " | ", NAME_LENGTH); if (strlen(attrib[i]) + strlen(getparam(str)) < NAME_LENGTH - 2) strlcat(attrib[i], getparam(str), NAME_LENGTH); else break; } } else break; } } else if (attr_flags[i] & AF_DATE) { sprintf(str, "y%d", i); year = atoi(getparam(str)); if (year < 100) year += 2000; sprintf(str, "m%d", i); month = atoi(getparam(str)); sprintf(str, "d%d", i); day = atoi(getparam(str)); memset(&ts, 0, sizeof(struct tm)); ts.tm_year = year - 1900; ts.tm_mon = month - 1; ts.tm_mday = day; ts.tm_hour = 12; if (month && day) { ltime = mktime(&ts); sprintf(attrib[i], "%d", (int) ltime); } else strcpy(attrib[i], ""); } else { strlcpy(attrib[i], getparam(ua), NAME_LENGTH); } } strlcpy(text, getparam("text"), TEXT_SIZE); for (i = 0; i < MAX_ATTACHMENTS; i++) { sprintf(str, "attachment%d", i); if (isparam(str)) strlcpy(att[i], getparam(str), 256); } /* get encoding */ strcpy(encoding, atoi(getparam("html")) == 1 ? "HTML" : "plain"); } else { if (message_id) { /* get message for reply/edit */ size = TEXT_SIZE; el_retrieve(lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, orig_tag, reply_tag, att, encoding, locked_by); if (bedit) { if (getcfg(lbs->name, "Use Lock", str) && atoi(str) == 1) { if (*getparam("full_name")) strcpy(str, getparam("full_name")); else strcpy(str, loc("user")); strcat(str, " "); strcat(str, loc("on")); strcat(str, " "); strcat(str, rem_host); el_lock_message(lbs, message_id, str); } } } } /* evaluate conditional attributes */ condition[0] = 0; for (index = 0; index < lbs->n_attr; index++) { for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { if (strchr(attr_options[index][i], '{') && strchr(attr_options[index][i], '}')) { strlcpy(str, attr_options[index][i], sizeof(str)); *strchr(str, '{') = 0; if (strieq(str, attrib[index])) { strlcpy(str, strchr(attr_options[index][i], '{') + 1, sizeof(str)); if (*strchr(str, '}')) *strchr(str, '}') = 0; if (condition[0] == 0) strlcpy(condition, str, sizeof(condition)); else { strlcat(condition, ",", sizeof(condition)); strlcat(condition, str, sizeof(condition)); } } } } } set_condition(condition); /* rescan attributes if condition set */ if (condition[0]) scan_attributes(lbs->name); /* check for maximum number of replies */ if (breply) { i = 0; p = strtok(reply_tag, ","); while (p) { i++; p = strtok(NULL, ","); } if (i >= MAX_REPLY_TO) { sprintf(str, loc("Maximum number of replies (%d) exceeded"), MAX_REPLY_TO); show_error(str); free(text); return; } } /* check for author */ if (bedit && getcfg(lbs->name, "Restrict edit", str) && atoi(str) == 1) { if (!is_author(lbs, attrib, owner)) { sprintf(str, loc("Only user %s can edit this entry"), owner); show_error(str); free(text); return; } } /* check for editing interval */ if (bedit && getcfg(lbs->name, "Restrict edit time", str)) { for (i = 0; i < *lbs->n_el_index; i++) if (lbs->el_index[i].message_id == message_id) break; if (i < *lbs->n_el_index && time(NULL) > lbs->el_index[i].file_time + atof(str) * 3600) { sprintf(str, loc("Entry can only be edited %1.2lg hours after creation"), atof(str)); show_error(str); free(text); return; } } /* remove attributes for replies */ if (breply) { getcfg(lbs->name, "Remove on reply", str); n = strbreak(str, list, MAX_N_ATTR, ","); for (i = 0; i < n; i++) for (j = 0; j < lbs->n_attr; j++) { if (strieq(attr_list[j], list[i])) attrib[j][0] = 0; } } /* subst attributes for replies */ if (breply) { for (index = 0; index < lbs->n_attr; index++) { sprintf(str, "Subst on reply %s", attr_list[index]); if (getcfg(lbs->name, str, preset)) { /* check if already second reply */ if (orig_tag[0] == 0) { /* do not format date for date attributes */ i = build_subst_list(lbs, slist, svalue, attrib, (attr_flags[index] & AF_DATE) == 0); sprintf(str, "%d", message_id); add_subst_list(slist, svalue, "message id", str, &i); add_subst_time(lbs, slist, svalue, "entry time", date, &i); strsubst(preset, slist, svalue, i); strcpy(attrib[index], preset); } } } } /* subst attributes for edits */ if (message_id && bedit && !breedit && !bupload) { for (index = 0; index < lbs->n_attr; index++) { sprintf(str, "Subst on edit %s", attr_list[index]); if (getcfg(lbs->name, str, preset)) { /* do not format date for date attributes */ i = build_subst_list(lbs, slist, svalue, attrib, (attr_flags[index] & AF_DATE) == 0); sprintf(str, "%d", message_id); add_subst_list(slist, svalue, "message id", str, &i); add_subst_time(lbs, slist, svalue, "entry time", date, &i); strsubst(preset, slist, svalue, i); if (strncmp(preset, "
", 4) == 0) strcpy(attrib[index], preset + 4); else strcpy(attrib[index], preset); } } } /* header */ show_html_header(lbs, FALSE, "ELOG", FALSE); /* java script for checking required attributes */ rsprintf("\n\n"); /* external script if requested */ if (isparam("js")) { rsprintf("\n\n"); } rsprintf("\n"); rsprintf("\n"); rsprintf("
\n"); /*---- add password in case cookie expires during edit ----*/ if (getcfg(lbs->name, "Write password", str)) rsprintf("\n", str); if (getcfg(lbs->name, "Password file", str)) { rsprintf("\n", getparam("unm")); rsprintf("\n", getparam("upwd")); } /*---- title row ----*/ show_standard_title(lbs->name, "", 0); /*---- menu buttons ----*/ rsprintf("\n"); /* default cmd */ rsprintf("\n", loc("Update")); rsprintf ("\n", loc("Submit")); rsprintf("\n", loc("Back")); rsprintf("\n\n"); /*---- entry form ----*/ /* table for two-column items */ rsprintf(""); /* print required message if one of the attributes has it set */ for (i = 0; i < lbs->n_attr; i++) { if (attr_flags[i] & AF_REQUIRED) { rsprintf ("\n", loc("Fields marked with"), loc("are required")); break; } } time(&now); if (bedit) { if (!getcfg(lbs->name, "Time format", format)) strcpy(format, DEFAULT_TIME_FORMAT); ltime = date_to_ltime(date); pts = localtime(<ime); strftime(str, sizeof(str), format, pts); } else { if (getcfg(lbs->name, "Time format", format)) strftime(str, sizeof(str), format, localtime(&now)); else strcpy(str, ctime(&now)); strcpy(date, ctime(&now)); date[24] = 0; } rsprintf("", loc("Entry time")); rsprintf("\n", date); /* display attributes */ for (index = 0; index < lbs->n_attr; index++) { strcpy(class_name, "attribname"); strcpy(class_value, "attribvalue"); input_size = 80; input_maxlen = NAME_LENGTH; format_flags = 0; strcpy(ua, attr_list[index]); btou(ua); sprintf(str, "Format %s", attr_list[index]); if (getcfg(lbs->name, str, format)) { n = strbreak(format, fl, 8, ","); if (n > 0) format_flags = atoi(fl[0]); if (n > 1) strlcpy(class_name, fl[1], sizeof(class_name)); if (n > 2) strlcpy(class_value, fl[2], sizeof(class_value)); if (n > 3 && atoi(fl[3]) > 0) input_size = atoi(fl[3]); if (n > 4 && atoi(fl[4]) > 0) input_maxlen = atoi(fl[4]); } strcpy(star, (attr_flags[index] & AF_REQUIRED) ? "*" : ""); /* check for preset string */ sprintf(str, "Preset %s", attr_list[index]); if ((i = getcfg(lbs->name, str, preset)) > 0) { if (!bedit || (breedit && i == 2)) { /* subst on reedit only if preset is under condition */ /* do not format date for date attributes */ i = build_subst_list(lbs, slist, svalue, attrib, (attr_flags[index] & AF_DATE) == 0); strsubst(preset, slist, svalue, i); /* check for index substitution */ if (!bedit && strchr(preset, '%')) { /* get index */ i = get_last_index(lbs, index); strcpy(str, preset); sprintf(preset, str, i + 1); } if (!strchr(preset, '%')) strcpy(attrib[index], preset); } } /* display text box */ rsprintf("\n"); /* if attribute cannot be changed, just display text */ if ((attr_flags[index] & AF_LOCKED) || (bedit && (attr_flags[index] & AF_FIXED_EDIT)) || (message_id && !bedit && (attr_flags[index] & AF_FIXED_REPLY))) { rsprintf("\n", ua, str); } } else { if (attr_options[index][0][0] == 0) { if (attr_flags[index] & AF_DATE) { year = month = day = 0; if (attrib[index][0]) { ltime = atoi(attrib[index]); pts = localtime(<ime); year = pts->tm_year + 1900; month = pts->tm_mon + 1; day = pts->tm_mday; } rsprintf("\n"); } else { /* show normal edit field */ rsprintf("\n"); } } else { if (strieq(attr_options[index][0], "boolean")) { /* display checkbox */ if (atoi(attrib[index]) == 1) rsprintf ("\n"); } else if (attr_flags[index] & AF_MULTI) { /* display multiple check boxes */ rsprintf("\n"); } else if (attr_flags[index] & AF_RADIO) { /* display radio buttons */ rsprintf("\n"); } else if (attr_flags[index] & AF_ICON) { /* display icons */ rsprintf("\n"); } else { rsprintf("\n"); } } } } } /* set textarea width */ width = 76; if (getcfg(lbs->name, "Message width", str)) width = atoi(str); /* increased width according to longest line */ if (message_id) { p = text; do { pend = strchr(p, '\n'); if (pend == NULL) pend = p + strlen(p); if ((int) pend - (int) p + 1 > width) width = (int) pend - (int) p + 1; if (*pend == 0) break; p = pend; while (*p && (*p == '\r' || *p == '\n')) p++; } while (1); /* leave space for '> ' */ if (!bedit) width += 2; } /* set textarea height */ height = 20; if (getcfg(lbs->name, "Message height", str)) height = atoi(str); rsprintf("\n"); if (!getcfg(lbs->name, "Enable attachments", str) || atoi(str) > 0) { i = 0; if (bedit) { /* show existing attachments */ for (i = 0; i < MAX_ATTACHMENTS; i++) if (att[i][0]) { rsprintf("\n", loc("Attachment"), i + 1); sprintf(str, "attachment%d", i); rsprintf("\n", i, loc("Delete")); } else break; } /* optional attachment comment */ if (getcfg(lbs->name, "Attachment comment", comment) && !message_id) { rsprintf("\n"); } /* field for add attachment */ if (att[MAX_ATTACHMENTS - 1][0]) { rsprintf("\n", loc("Maximum number of attachments reached")); rsprintf("\n"); } else { rsprintf("\n", loc("Attachment"), i + 1); rsprintf ("\n"); } } rsprintf("
%s * %s
%s:%s\n", str); rsprintf("
%s%s:", attr_list[index], star); /* show optional comment */ sprintf(str, "Comment %s", attr_list[index]); if (getcfg(lbs->name, str, comment)) rsprintf("
%s\n", comment); rsprintf("
\n"); rsputs2(attrib[index]); rsprintf(" "); if (attr_flags[index] & AF_MULTI) { for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { sprintf(str, "%s_%d", ua, i); if (strstr(attrib[index], attr_options[index][i])) rsprintf("\n", str, attr_options[index][i]); } } else if (attr_flags[index] & AF_RADIO) { for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { sprintf(str, "%s_%d", ua, i); if (strstr(attrib[index], attr_options[index][i])) rsprintf("\n", str, attr_options[index][i]); } } else if (attr_flags[index] & AF_ICON) { for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { sprintf(str, "%s_%d", ua, i); if (strstr(attrib[index], attr_options[index][i])) rsprintf("\n", str, attr_options[index][i]); } } else { strencode2(str, attrib[index]); rsprintf("
"); sprintf(str, "%d", index); show_date_selector(day, month, year, str); rsprintf("
"); strencode2(str, attrib[index]); rsprintf ("\n", input_size, input_maxlen, ua, str); rsprintf("
\n", ua); else rsprintf ("\n", ua); } else { sprintf(str, loc("Add %s"), attr_list[index]); if (strieq(getparam("extend"), str)) { rsprintf("\n"); rsprintf(""); rsprintf(loc("Add new option here"), attr_list[index]); rsprintf(" : \n"); rsprintf ("\n", input_maxlen, ua, attrib[index]); rsprintf("
\n"); for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { sprintf(str, "%s_%d", ua, i); if (strstr(attrib[index], attr_options[index][i])) rsprintf ("\n", str, str, attr_options[index][i]); else rsprintf ("\n", str, str, attr_options[index][i]); rsprintf("\n", str, attr_options[index][i]); if (format_flags & AFF_MULTI_LINE) rsprintf("
"); } if (attr_flags[index] & AF_EXTENDABLE) { sprintf(str, loc("Add %s"), attr_list[index]); rsprintf("\n", str); } rsprintf("
\n"); for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { if (strstr(attrib[index], attr_options[index][i])) rsprintf ("\n", attr_options[index][i], ua, attr_options[index][i]); else rsprintf ("\n", attr_options[index][i], ua, attr_options[index][i]); rsprintf("\n", attr_options[index][i], attr_options[index][i]); if (format_flags & AFF_MULTI_LINE) rsprintf("
"); } if (attr_flags[index] & AF_EXTENDABLE) { sprintf(str, loc("Add %s"), attr_list[index]); rsprintf("\n", str); } rsprintf("
\n"); for (i = 0; i < MAX_N_LIST && attr_options[index][i][0]; i++) { if (strstr(attrib[index], attr_options[index][i])) rsprintf ("", ua, attr_options[index][i]); else rsprintf("", ua, attr_options[index][i]); sprintf(str, "Icon comment %s", attr_options[index][i]); getcfg(lbs->name, str, comment); if (comment[0]) rsprintf("\"%s\"\n", attr_options[index][i], comment); else rsprintf("\n", attr_options[index][i]); if (format_flags & AFF_MULTI_LINE) rsprintf("
"); } rsprintf("
\n"); /* display drop-down box */ rsprintf("\n"); if (is_cond_attr(index)) { /* show "update" button only of javascript is not enabled */ rsprintf("\n"); } if (attr_flags[index] & AF_EXTENDABLE) { sprintf(str, loc("Add %s"), attr_list[index]); rsprintf("\n", str); } rsprintf("
\n"); if (breply) /* hidden text for original message */ rsprintf("\n", message_id); if (breedit || bupload) /* hidden text for original message */ rsprintf("\n", getparam("reply_to")); if (bedit && message_id) rsprintf("\n", message_id); if (getcfg(lbs->name, "Message comment", comment) && !message_id) { rsputs(comment); rsputs("
\n"); } if (!getcfg(lbs->name, "Show text", str) || atoi(str) == 1) { rsprintf("
\n"); /* HTML check box */ if (message_id) { if (getcfg(lbs->name, "HTML default", str)) { if (atoi(str) < 2) { if (encoding[0] == 'H') rsprintf("%s\n", loc("Submit as HTML text")); else rsprintf("%s\n", loc("Submit as HTML text")); } else if (atoi(str) == 3) { rsprintf("\n"); } } else { if (encoding[0] == 'H') rsprintf("%s\n", loc("Submit as HTML text")); else rsprintf("%s\n", loc("Submit as HTML text")); } } else { if (getcfg(lbs->name, "HTML default", str)) { if (atoi(str) == 0) { rsprintf("%s\n", loc("Submit as HTML text")); } else if (atoi(str) == 1) { rsprintf("%s\n", loc("Submit as HTML text")); } else if (atoi(str) == 3) { rsprintf("\n"); } } else rsprintf("%s\n", loc("Submit as HTML text")); } } /* Suppress email check box */ if (!(bedit && !breedit && !bupload && getcfg(lbs->name, "Suppress Email on edit", str) && atoi(str) == 1)) { if (getcfg(lbs->name, "Suppress default", str)) { if (atoi(str) == 0) { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress Email notification")); } else if (atoi(str) == 1) { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress Email notification")); } } else { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress Email notification")); } } /* Suppress execute shell check box */ if (!bedit && getcfg(lbs->name, "Execute new", str)) { if (getcfg(lbs->name, "Suppress execute default", str)) { if (atoi(str) == 0) { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress shell execution")); } else if (atoi(str) == 1) { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress shell execution")); } } else { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress shell execution")); } } if (bedit && getcfg(lbs->name, "Execute edit", str)) { if (getcfg(lbs->name, "Suppress execute default", str)) { if (atoi(str) == 0) { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress shell execution")); } else if (atoi(str) == 1) { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress shell execution")); } } else { rsprintf("        \n"); rsprintf("%s\n", loc("Suppress shell execution")); } } /* Resubmit check box */ if (bedit) { if (getcfg(lbs->name, "Resubmit default", str)) { if (atoi(str) == 0) { rsprintf("        \n"); rsprintf("%s\n", loc("Resubmit as new entry")); } else if (atoi(str) == 1) { rsprintf("        \n"); rsprintf("%s\n", loc("Resubmit as new entry")); } } else { rsprintf("        \n"); rsprintf("%s\n", loc("Resubmit as new entry")); } } rsprintf("
%s %d:\n"); rsprintf("\n", str, att[i]); rsprintf("%s\n", att[i] + 14); rsprintf ("  
\n"); rsputs(comment); rsputs("
%s
%s %d:\n"); rsprintf("  \n", loc("Upload")); rsprintf("
\n"); /*---- menu buttons again ----*/ rsprintf("\n"); rsprintf ("\n", loc("Submit")); rsprintf("\n", loc("Back")); rsprintf("\n\n"); rsprintf("\n"); show_bottom_text(lbs); rsprintf("
\r\n"); /* rescan unconditional attributes */ if (condition[0]) scan_attributes(lbs->name); free(text); } /*------------------------------------------------------------------*/ void show_find_form(LOGBOOK * lbs) { int i, j; char str[NAME_LENGTH], mode[NAME_LENGTH], comment[NAME_LENGTH], option[NAME_LENGTH]; /*---- header ----*/ show_standard_header(lbs, FALSE, loc("ELOG find"), NULL); /*---- title ----*/ show_standard_title(lbs->name, "", 0); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n", loc("Search")); rsprintf("\n", loc("Reset Form")); rsprintf("\n", loc("Back")); rsprintf("\n\n"); /*---- entry form ----*/ rsprintf("\n"); rsprintf("%s:  ", loc("Mode")); if (!getcfg(lbs->name, "Display mode", mode)) strcpy(mode, "Full"); if (!getcfg(lbs->name, "Show text", str) || atoi(str) == 1) { if (strieq(mode, "Full")) rsprintf(""); else rsprintf(""); rsprintf("\n", loc("Display full entries")); if (strieq(mode, "Summary")) rsprintf (""); else rsprintf(""); rsprintf("\n", loc("Summary only")); } else { if (strieq(mode, "Full") || strieq(mode, "Summary")) rsprintf (""); else rsprintf(""); rsprintf("\n", loc("Summary")); } if (strieq(mode, "Threaded")) rsprintf (""); else rsprintf(""); rsprintf("\n", loc("Display threads")); if (strieq(mode, "CSV1")) rsprintf(""); else rsprintf(""); rsprintf("\n", loc("CSV (\",\" separated)")); if (strieq(mode, "CSV2")) rsprintf(""); else rsprintf(""); rsprintf("\n", loc("CSV (\";\" separated)")); if (strieq(mode, "XML")) rsprintf(""); else rsprintf(""); rsprintf("\n"); rsprintf("\n"); rsprintf("%s:
", loc("Options")); if (!getcfg(lbs->name, "Number attachments", str) || atoi(str) > 0) { rsprintf(""); rsprintf("\n", loc("Show attachments")); } rsprintf(""); rsprintf("\n", loc("Printable output")); if (getcfg(lbs->name, "Reverse sort", str) && atoi(str) == 1) rsprintf(""); else rsprintf(""); rsprintf("\n", loc("Sort in reverse order")); /* count logbooks */ for (i = 0;; i++) { if (!enumgrp(i, str)) break; if (is_logbook(str)) continue; } if (i > 2) { if (!getcfg(lbs->name, "Search all logbooks", str) || atoi(str) == 1) { rsprintf("\n"); rsprintf("
\n", loc("Search all logbooks")); } } rsprintf(loc("Display")); if (!getcfg(lbs->name, "Entries per page", str)) strcpy(str, "20"); rsprintf(" ", str); rsprintf(loc("entries per page")); rsprintf("\n"); rsprintf("%s:
", loc("Filters")); /* table for two-column items */ rsprintf("\n"); rsprintf("", loc("Entry date")); rsprintf("\n"); for (i = 0; i < lbs->n_attr; i++) { rsprintf("", attr_list[i]); rsprintf("\n"); } rsprintf("", loc("Text")); rsprintf ("\n", loc("(case insensitive substring)")); rsprintf("
%s:\n"); rsprintf("\n"); rsprintf("
%s:", loc("Start")); show_date_selector(0, 0, 0, "a"); rsprintf("  /  %s: ", loc("Show last")); rsprintf(" \n"); rsprintf("
%s:", loc("End")); show_date_selector(0, 0, 0, "b"); rsprintf("
%s:"); if (attr_options[i][0][0] == 0) { if (attr_flags[i] & AF_DATE) { rsprintf("\n"); rsprintf("\n"); rsprintf("
%s:", loc("Start")); sprintf(str, "%da", i); show_date_selector(0, 0, 0, str); rsprintf("
%s:", loc("End")); sprintf(str, "%db", i); show_date_selector(0, 0, 0, str); rsprintf("
\n"); } else { rsprintf("\n", attr_list[i]); rsprintf("%s\n", loc("(case insensitive substring)")); } } else { if (strieq(attr_options[i][0], "boolean")) rsprintf("\n", attr_list[i]); /* display image for icon */ else if (attr_flags[i] & AF_ICON) { for (j = 0; j < MAX_N_LIST && attr_options[i][j][0]; j++) { strcpy(option, attr_options[i][j]); if (strchr(option, '{')) *strchr(option, '{') = 0; sprintf(str, "Icon comment %s", option); getcfg(lbs->name, str, comment); rsprintf("", attr_list[i], option); if (comment[0]) rsprintf("\"%s\"\n", option, comment); else rsprintf("\n", option); } } else { rsprintf("\n"); } } rsprintf("
%s:\n"); rsprintf("%s
\n"); rsprintf("\n"); rsprintf("\n", loc("Search text also in attributes")); rsprintf("
\n"); show_bottom_text(lbs); rsprintf("\r\n"); } /*------------------------------------------------------------------*/ const char *find_section(const char *buf, const char *name) { const char *pstart; char *pstr, str[80]; do { if (*buf == '[') { pstart = buf; buf++; pstr = str; while (*buf && *buf != ']' && *buf != '\n' && *buf != '\r') *pstr++ = *buf++; *pstr = 0; if (strieq(str, name)) return pstart; } if (buf) buf = strchr(buf, '\n'); if (buf) buf++; if (buf && *buf == '\r') buf++; } while (buf); return NULL; } /*------------------------------------------------------------------*/ const char *find_next_section(const char *buf) { do { if (*buf == '[') return buf; if (buf) buf = strchr(buf, '\n'); if (buf) buf++; } while (buf); return NULL; } /*------------------------------------------------------------------*/ void load_config_section(char *section, char **buffer, char *error) { int fh, length; char *p; error[0] = 0; *buffer = NULL; fh = open(config_file, O_RDONLY | O_BINARY); if (fh < 0) { sprintf(error, "Cannot read configuration file \"%s\"", config_file); return; } length = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); *buffer = malloc(length + 1); if (*buffer == NULL) { close(fh); strcpy(error, "Error: out of memory"); return; } read(fh, *buffer, length); (*buffer)[length] = 0; close(fh); if ((p = (char *) find_section(*buffer, section)) != NULL) { if (strchr(p, ']')) { p = strchr(p, ']') + 1; while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; } strlcpy(*buffer, p, length); if ((p = (char *) find_next_section(*buffer + 1)) != NULL) { *p = 0; /* strip trailing newlines */ if (p) { p--; while (p > *buffer && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t')) *p-- = 0; } } else { p = *buffer + strlen(*buffer) - 1; while (p > *buffer && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t')) *p-- = 0; } } } /*------------------------------------------------------------------*/ void show_admin_page(LOGBOOK * lbs, char *top_group) { int rows, cols; char *buffer, error_str[256]; char section[NAME_LENGTH], str[NAME_LENGTH], grp[NAME_LENGTH]; /*---- header ----*/ sprintf(str, "ELOG %s", loc("Admin")); show_html_header(lbs, FALSE, str, TRUE); rsprintf ("
\n"); /*---- title ----*/ show_standard_title(lbs->name, "", 0); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n", loc("Save")); rsprintf("\n", loc("Cancel")); if (lbs->top_group[0] && (!top_group || strieq(top_group, "global"))) { if (!getcfg("global", "Admin user", str) || strstr(str, getparam("unm")) != 0) { if (lbs->top_group[0]) { sprintf(str, "global %s", lbs->top_group); if (is_group(str)) { sprintf(grp, "[global %s]", lbs->top_group); sprintf(str, loc("Change %s"), grp); rsprintf("\n", str); } } } } if (is_group("global") && !strieq(top_group, "global")) { if (!getcfg_simple("global", "Admin user", str) || strstr(str, getparam("unm")) != 0) { sprintf(str, loc("Change %s"), "[global]"); rsprintf("\n", str); } } if (top_group) { if (strieq(top_group, "global")) { rsprintf("\n"); strcpy(str, "[global]"); } else { rsprintf("\n", top_group); sprintf(str, "[global %s]", top_group); } rsprintf("
%s
", str); } rsprintf("
\n\n"); /*---- entry form ----*/ rsprintf("\n"); /* extract section of current logbook */ if (top_group) { if (strieq(top_group, "global")) strcpy(section, "global"); else sprintf(section, "global %s", top_group); } else strcpy(section, lbs->name); load_config_section(section, &buffer, error_str); if (error_str[0]) { rsprintf("\n"); rsprintf("\r\n"); return; } if (getcfg(section, "Admin textarea", str) && strchr(str, ',') != NULL) { cols = atoi(str); rows = atoi(strchr(str, ',') + 1); } else { cols = 120; rows = 30; } rsprintf("\n"); /* put link for config page */ rsprintf ("
Syntax Help"); rsprintf("\n"); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n", loc("Save")); rsprintf("\n", loc("Cancel")); rsprintf("\n\n"); rsprintf("\n\n"); show_bottom_text(lbs); rsprintf("
\r\n"); } /*------------------------------------------------------------------*/ void remove_crlf(char *buffer) { char *p; p = buffer; while ((p = strstr(p, "\r\n")) != NULL) { strcpy(p, p + 1); } } /*------------------------------------------------------------------*/ int save_admin_config(char *section, char *buffer, char *error) { int fh, i, length; char *buf, *buf2, *p1, *p2; error[0] = 0; fh = open(config_file, O_RDWR | O_BINARY, 644); if (fh < 0) { sprintf(error, loc("Cannot open file %s"), config_file); strcat(error, ": "); strcat(error, strerror(errno)); return 0; } #ifdef OS_UNIX /* under unix, convert CRLF to CR */ remove_crlf(buffer); #endif /* read previous contents */ length = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); buf = malloc(length + strlen(buffer) + 1); assert(buf); read(fh, buf, length); buf[length] = 0; /* find previous logbook config */ p1 = (char *) find_section(buf, section); p2 = (char *) find_next_section(p1 + 1); /* save tail */ buf2 = NULL; if (p2) { buf2 = malloc(strlen(p2) + 1); assert(buf2); strlcpy(buf2, p2, strlen(p2) + 1); } /* combine old and new config */ #ifdef OS_UNIX sprintf(p1, "[%s]\n", section); strcat(p1, buffer); strcat(p1, "\n\n"); #else sprintf(p1, "[%s]\r\n", section); strcat(p1, buffer); strcat(p1, "\r\n\r\n"); #endif if (p2) { strlcat(p1, buf2, length + strlen(buffer) + 1); free(buf2); } lseek(fh, 0, SEEK_SET); i = write(fh, buf, strlen(buf)); if (i < (int) strlen(buf)) { sprintf(error, loc("Cannot write to %s"), config_file); strcat(error, ": "); strcat(error, strerror(errno)); close(fh); free(buf); return 0; } #ifdef _MSC_VER chsize(fh, TELL(fh)); #else ftruncate(fh, TELL(fh)); #endif close(fh); free(buf); /* force re-read of config file */ check_config(); return 1; } /*------------------------------------------------------------------*/ int save_user_config(LOGBOOK * lbs, char *user, BOOL new_user, BOOL activate) { char file_name[256], str[256], line[256], *buf, *pl, new_pwd[80], new_pwd2[80]; char smtp_host[256], email_addr[256], mail_from[256], subject[256], mail_text[2000]; char admin_user[80], enc_pwd[80], url[256]; int i, fh, size, self_register; /* check self register flag */ self_register = 0; if (getcfg(lbs->name, "Self register", str)) self_register = atoi(str); if (!activate) { /* check for hidden password */ if (isparam("hpwd")) { strcpy(new_pwd, getparam("hpwd")); } else { /* check if passwords match */ do_crypt(getparam("newpwd"), new_pwd); do_crypt(getparam("newpwd2"), new_pwd2); if (strcmp(new_pwd, new_pwd2) != 0) { show_error(loc("New passwords do not match, please retype")); return 0; } } /* check if user exists */ if (new_user && self_register == 3) { if (get_user_line(lbs->name, user, NULL, NULL, NULL, NULL) == 1) { sprintf(str, "%s \"%s\" %s", loc("Login name"), user, loc("exists already")); show_error(str); return 0; } } } if (activate || !new_user || self_register != 3) { /* do not save in mode 3 */ getcfg(lbs->name, "Password file", str); if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } fh = open(file_name, O_RDWR | O_BINARY | O_CREAT, 644); if (fh < 0) { sprintf(str, loc("Cannot open file %s"), file_name); show_error(str); return 0; } lseek(fh, 0, SEEK_END); size = TELL(fh); lseek(fh, 0, SEEK_SET); buf = malloc(size + 1); read(fh, buf, size); buf[size] = 0; pl = buf; while (pl < buf + size) { for (i = 0; pl[i] && pl[i] != '\r' && pl[i] != '\n'; i++) line[i] = pl[i]; line[i] = 0; /* skip outcommented lines */ if (line[0] == ';' || line[0] == '#') { pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; continue; } if (line[0] == 0) break; strcpy(str, line); if (strchr(str, ':')) *strchr(str, ':') = 0; if (strcmp(str, user) == 0) { if (new_user) { sprintf(str, "%s \"%s\" %s", loc("Login name"), user, loc("exists already")); show_error(str); free(buf); close(fh); return 0; } break; } pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; } if (new_user) { lseek(fh, 0, SEEK_END); if (strlen(buf) != 0 && (buf[strlen(buf) - 1] != '\r' && buf[strlen(buf) - 1] != '\n')) write(fh, "\n", 1); if (activate) sprintf(str, "%s:%s:%s:%s:%s\n", getparam("new_user_name"), getparam("encpwd"), getparam("new_full_name"), getparam("new_user_email"), getparam("email_notify")); else sprintf(str, "%s:%s:%s:%s:%s\n", getparam("new_user_name"), new_pwd, getparam("new_full_name"), getparam("new_user_email"), getparam("email_notify")); write(fh, str, strlen(str)); } else { /* replace line */ lseek(fh, 0, SEEK_SET); write(fh, buf, pl - buf); sprintf(str, "%s:%s:%s:%s:%s\n", getparam("new_user_name"), new_pwd, getparam("new_full_name"), getparam("new_user_email"), getparam("email_notify")); write(fh, str, strlen(str)); pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; write(fh, pl, strlen(pl)); #ifdef _MSC_VER chsize(fh, TELL(fh)); #else ftruncate(fh, TELL(fh)); #endif } free(buf); close(fh); } /* if requested, send notification email to admin user */ if (new_user && (self_register == 2 || self_register == 3) && !isparam("admin")) { if (!getcfg("global", "SMTP host", smtp_host)) { show_error(loc ("No SMTP host defined in [global] section of configuration file")); return 0; } /* try to get URL from referer */ if (!getcfg("global", "URL", url)) { if (referer[0]) strcpy(url, referer); else { if (tcp_port == 80) sprintf(url, "http://%s/", host_name); else sprintf(url, "http://%s:%d/", host_name, tcp_port); } } else { if (url[strlen(url) - 1] != '/') strlcat(url, "/", sizeof(url)); if (lbs) { strlcat(url, lbs->name_enc, sizeof(url)); strlcat(url, "/", sizeof(url)); } } if (!getcfg(lbs->name, "Use Email from", mail_from)) sprintf(mail_from, "ELog@%s", host_name); if (activate) { sprintf(subject, loc("Your ELOG account has been activated")); sprintf(mail_text, loc("Your ELOG account has been activated on host")); sprintf(mail_text + strlen(mail_text), " %s", host_name); sprintf(mail_text + strlen(mail_text), ".\r\n\r\n"); sprintf(url + strlen(url), "?cmd=Login&unm=%s", getparam("new_user_name")); sprintf(mail_text + strlen(mail_text), "%s %s\r\n", loc("You can access it at"), url); sendmail(lbs, smtp_host, mail_from, getparam("new_user_email"), subject, mail_text, TRUE, url, NULL); } else { if (getcfg(lbs->name, "Admin user", admin_user)) { pl = strtok(admin_user, " ,"); while (pl) { get_user_line(lbs->name, pl, NULL, NULL, email_addr, NULL); if (email_addr[0]) { /* compose subject */ if (self_register == 3) { if (lbs) sprintf(subject, loc("Registration request on logbook \"%s\""), lbs->name); else sprintf(subject, loc("Registration request on host \"%s\""), host_name); sprintf(mail_text, loc("A new ELOG user wants to register on \"%s\""), host_name); } else { if (lbs) sprintf(subject, loc("User \"%s\" registered on logbook \"%s\""), getparam("new_user_name"), lbs->name); else sprintf(subject, loc("User \"%s\" registered on host \"%s\""), getparam("new_user_name"), host_name); sprintf(mail_text, loc("A new ELOG user has been registered on %s"), host_name); } sprintf(mail_text + strlen(mail_text), "\r\n\r\n"); if (lbs) sprintf(mail_text + strlen(mail_text), "%s : %s\r\n", loc("Logbook"), lbs->name); else sprintf(mail_text + strlen(mail_text), "%s : %s\r\n", loc("Host"), host_name); sprintf(mail_text + strlen(mail_text), "%s : %s\r\n", loc("Login name"), getparam("new_user_name")); sprintf(mail_text + strlen(mail_text), "%s : %s\r\n", loc("Full name"), getparam("new_full_name")); sprintf(mail_text + strlen(mail_text), "%s : %s\r\n", loc("Email"), getparam("new_user_email")); if (self_register == 3) { sprintf(mail_text + strlen(mail_text), "\r\n%s:\r\n", loc("Hit following URL to activate that account")); sprintf(mail_text + strlen(mail_text), "\r\nURL : %s", url); strcpy(str, getparam("new_full_name")); url_encode(str, sizeof(str)); do_crypt(getparam("newpwd"), enc_pwd); url_encode(enc_pwd, sizeof(enc_pwd)); sprintf(mail_text + strlen(mail_text), "?cmd=Activate&new_user_name=%s&new_full_name=%s&new_user_email=%s&email_notify=%s&encpwd=%s&unm=%s\r\n", getparam("new_user_name"), str, getparam("new_user_email"), getparam("email_notify"), enc_pwd, pl); } else { sprintf(mail_text + strlen(mail_text), "\r\n%s URL : %s?cmd=Config&cfg_user=%s&unm=%s\r\n", loc("Logbook"), url, getparam("new_user_name"), pl); } sendmail(lbs, smtp_host, mail_from, email_addr, subject, mail_text, TRUE, url, NULL); } pl = strtok(NULL, " ,"); } } if (self_register == 3) { sprintf(str, "?cmd=%s", loc("Requested")); redirect(lbs, str); return 0; } } } /* if user name changed, set cookie */ if (strcmp(user, getparam("new_user_name")) != 0 && strcmp(user, getparam("unm")) == 0) { set_login_cookies(lbs, getparam("new_user_name"), new_pwd); return 0; } /* if new user, login as this user */ if (new_user && !*getparam("unm")) { set_login_cookies(lbs, getparam("new_user_name"), new_pwd); return 0; } return 1; } /*------------------------------------------------------------------*/ int remove_user(LOGBOOK * lbs, char *user) { char file_name[256], str[256], line[256], *buf, *pl; int i, fh, size; getcfg(lbs->name, "Password file", str); if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } fh = open(file_name, O_RDWR | O_BINARY, 0644); if (fh < 0) { sprintf(str, loc("Cannot open file %s"), file_name); strcat(str, ": "); strcat(str, strerror(errno)); show_error(str); return 0; } lseek(fh, 0, SEEK_END); size = TELL(fh); lseek(fh, 0, SEEK_SET); buf = malloc(size + 1); read(fh, buf, size); buf[size] = 0; pl = buf; while (pl < buf + size) { for (i = 0; pl[i] && pl[i] != '\r' && pl[i] != '\n'; i++) line[i] = pl[i]; line[i] = 0; if (line[0] == ';' || line[0] == '#' || line[0] == 0) { pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; continue; } strcpy(str, line); if (strchr(str, ':')) *strchr(str, ':') = 0; if (strcmp(str, user) == 0) break; pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; } /* remove line */ lseek(fh, 0, SEEK_SET); write(fh, buf, pl - buf); pl += strlen(line); while (*pl && (*pl == '\r' || *pl == '\n')) pl++; write(fh, pl, strlen(pl)); #ifdef _MSC_VER chsize(fh, TELL(fh)); #else ftruncate(fh, TELL(fh)); #endif free(buf); close(fh); return 1; } /*------------------------------------------------------------------*/ int ascii_compare(const void *s1, const void *s2) { return stricmp(*(char **) s1, *(char **) s2); } /*------------------------------------------------------------------*/ void show_config_page(LOGBOOK * lbs) { char str[256], user[80], password[80], full_name[80], user_email[80], email_notify[256], logbook[256]; char **user_list; int i, n; if (lbs) strcpy(logbook, lbs->name); else strcpy(logbook, "global"); /*---- header ----*/ show_standard_header(lbs, TRUE, loc("ELOG user config"), "."); /*---- title ----*/ show_standard_title(logbook, "", 0); /* get user */ strcpy(user, getparam("unm")); if (isparam("cfg_user")) strcpy(user, getparam("cfg_user")); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n", loc("Config")); // for select javascript rsprintf("\n", loc("Save")); rsprintf("\n", loc("Back")); rsprintf("\n", user); rsprintf("\n\n"); /* table for two-column items */ rsprintf(""); rsprintf("\n"); /*---- if admin user, show user list ----*/ if (getcfg(logbook, "Admin user", str) && strstr(str, getparam("unm")) != 0) { rsprintf("\n"); rsprintf("\n", loc("Select user")); rsprintf("\n", loc("Login name")); if (get_user_line(logbook, user, password, full_name, user_email, email_notify) != 1) sprintf(str, loc("User [%s] has been deleted"), user); else strcpy(str, user); rsprintf("\n", str); rsprintf("\n", loc("Full name")); rsprintf("\n", full_name); rsprintf("\n"); rsprintf ("\n"); else rsprintf("\n"); rsprintf("
%s:\n"); /* show "update" button only of javascript is not enabled */ rsprintf("\n"); } /*---- entry form ----*/ rsprintf("
%s:
%s:
Email:    \n", user_email); rsprintf("%s:\n", loc("Enable email notifications")); if (email_notify[0]) rsprintf("
\n"); rsprintf("\n"); rsprintf("\n", loc("Change password")); rsprintf("\n", loc("Remove user")); if (!getcfg(logbook, "Admin user", str) || (getcfg(logbook, "Admin user", str) && strstr(str, getparam("unm")) != 0)) { rsprintf("\n", loc("New user")); rsprintf("\n", loc("Change elogd.cfg")); } /* hidden field for password */ rsprintf("\n", password); rsprintf("\n\n"); show_bottom_text(lbs); rsprintf("\r\n"); } /*------------------------------------------------------------------*/ void show_forgot_pwd_page(LOGBOOK * lbs) { int i; char str[1000], login_name[256], full_name[256], user_email[256], name[256], pwd[256], redir[256], pwd_encrypted[256], smtp_host[256], mail_from[256], subject[256], mail_text[1000], url[1000]; if (isparam("login_name")) { /* seach in pwd file */ strcpy(name, getparam("login_name")); for (i = 0;; i++) { if (!enum_user_line(lbs, i, login_name)) break; get_user_line(lbs->name, login_name, NULL, full_name, user_email, NULL); if (strieq(name, login_name) || strieq(name, full_name) || strieq(name, user_email)) { if (user_email[0] == 0) { sprintf(str, loc("No Email address registered with user name \"%s\""), name); show_error(str); return; } /* create random password */ srand((unsigned int) time(NULL)); for (i = 0; i < 6; i++) str[i] = rand() & 0x7F; str[i] = 0; base64_encode(str, pwd); do_crypt(pwd, pwd_encrypted); /* send email with new password */ if (!getcfg("global", "SMTP host", smtp_host)) { show_error(loc ("No SMTP host defined in [global] section of configuration file")); return; } /* try to get URL from referer */ if (!getcfg("global", "URL", url)) { if (referer[0]) strcpy(url, referer); else { if (tcp_port == 80) sprintf(url, "http://%s/", host_name); else sprintf(url, "http://%s:%d/", host_name, tcp_port); } } else { if (url[strlen(url) - 1] != '/') strlcat(url, "/", sizeof(url)); if (lbs) { strlcat(url, lbs->name_enc, sizeof(url)); strlcat(url, "/", sizeof(url)); } } sprintf(redir, "?cmd=%s&old_pwd=%s", loc("Change password"), pwd); url_encode(redir, sizeof(redir)); sprintf(str, "?redir=%s&uname=%s&upassword=%s", redir, login_name, pwd); strlcat(url, str, sizeof(url)); if (!getcfg(lbs->name, "Use Email from", mail_from)) sprintf(mail_from, "ELog@%s", host_name); if (lbs) sprintf(subject, loc("Password recovery for ELOG %s"), lbs->name); else sprintf(subject, loc("Password recovery for ELOG %s"), host_name); sprintf(mail_text, loc("A new password has been created for you on host %s"), host_name); strlcat(mail_text, ".\r\n", sizeof(mail_text)); strlcat(mail_text, loc ("Please log on by clicking on following link and change your password"), sizeof(mail_text)); strlcat(mail_text, ":\r\n\r\n", sizeof(mail_text)); strlcat(mail_text, url, sizeof(mail_text)); strlcat(mail_text, "\r\n\r\n", sizeof(mail_text)); sprintf(mail_text + strlen(mail_text), "ELOG Version %s\r\n", VERSION); if (sendmail (lbs, smtp_host, mail_from, user_email, subject, mail_text, TRUE, url, NULL) != -1) { /* save new password */ change_pwd(lbs, login_name, pwd_encrypted); /* show notification web page */ show_standard_header(lbs, FALSE, loc("ELOG password recovery"), ""); rsprintf(""); rsprintf("
\n"); rsprintf(loc("A new password for user \"%s\" has been sent to %s"), full_name, user_email); rsprintf("
\n"); show_bottom_text(lbs); rsprintf("\n"); return; } else { sprintf(str, loc("Error sending Email via \"%s\""), smtp_host); show_error(str); return; } } } if (strchr(name, '@')) sprintf(str, loc("Email address \"%s\" not registered"), name); else sprintf(str, loc("User name \"%s\" not registered"), name); show_error(str); return; } else { /*---- header ----*/ show_standard_header(lbs, TRUE, loc("ELOG password recovery"), NULL); rsprintf(""); /*---- entry form ----*/ rsprintf("\n", loc("Enter your user name or email address")); rsprintf("\n"); rsprintf ("
%s
\n"); rsprintf("\n", loc("Forgot")); rsprintf("
\n", loc("Submit")); rsprintf("
\n\n"); show_bottom_text(lbs); rsprintf("\r\n"); } } /*------------------------------------------------------------------*/ void show_new_user_page(LOGBOOK * lbs) { /*---- header ----*/ show_html_header(NULL, TRUE, loc("ELOG new user"), TRUE); rsprintf("

\n"); show_top_text(lbs); rsprintf("

\n\n"); /*---- title ----*/ if (lbs) show_standard_title(lbs->name, "", 1); else show_standard_title("ELOG", "", 1); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n", loc("Save")); rsprintf("\n", loc("Cancel")); rsprintf("\n\n"); /* table for two-column items */ rsprintf(""); rsprintf("\n"); /*---- entry form ----*/ rsprintf("\n", loc("Login name")); rsprintf ("\n", loc("name may not contain blanks")); rsprintf("\n", loc("Full name")); rsprintf("\n"); rsprintf("\n"); rsprintf("\n"); rsprintf("\n"); rsprintf("\n", loc("Password")); rsprintf("\n", loc("Retype password")); rsprintf("
%s:(%s)
%s:
Email:
%s: \n", loc("Enable email notifications")); rsprintf("
%s:\n"); rsprintf("
%s:\n"); rsprintf("
\n"); rsprintf("\n\n"); show_bottom_text(lbs); rsprintf("\r\n"); } /*------------------------------------------------------------------*/ void show_elog_delete(LOGBOOK * lbs, int message_id) { int i, status, reply, next; char str[256], in_reply_to[80], reply_to[MAX_REPLY_TO * 10], owner[256]; char attrib[MAX_N_ATTR][NAME_LENGTH]; /* redirect if confirm = NO */ if (getparam("confirm") && *getparam("confirm") && strcmp(getparam("confirm"), loc("No")) == 0) { if (message_id) { sprintf(str, "%d", message_id); redirect(lbs, str); } else { strlcpy(str, getparam("lastcmd"), sizeof(str)); url_decode(str); redirect(lbs, str); } return; } if (getparam("confirm") && *getparam("confirm")) { if (strcmp(getparam("confirm"), loc("Yes")) == 0) { if (message_id) { /* delete message */ status = el_delete_message(lbs, message_id, TRUE, NULL, TRUE, TRUE); if (status != EL_SUCCESS) { sprintf(str, "%s = %d", loc("Error deleting message: status"), status); show_error(str); return; } else { strcpy(str, getparam("nextmsg")); if (atoi(str) == 0) sprintf(str, "%d", el_search_message(lbs, EL_LAST, 0, TRUE)); if (atoi(str) == 0) redirect(lbs, ""); else redirect(lbs, str); return; } } else { for (i = reply = 0; i < atoi(getparam("nsel")); i++) { sprintf(str, "s%d", i); if (isparam(str)) status = el_delete_message(lbs, atoi(getparam(str)), TRUE, NULL, TRUE, TRUE); } redirect(lbs, getparam("lastcmd")); return; } } } else { /* check if at least one message is selected */ if (!message_id) { for (i = 0; i < atoi(getparam("nsel")); i++) { sprintf(str, "s%d", i); if (isparam(str)) break; } if (i == atoi(getparam("nsel"))) { show_error(loc("No entry selected for deletion")); return; } } /* check for author */ if (getcfg(lbs->name, "Restrict edit", str) && atoi(str) == 1) { /* get message for reply/edit */ el_retrieve(lbs, message_id, NULL, attr_list, attrib, lbs->n_attr, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (!is_author(lbs, attrib, owner)) { sprintf(str, loc("Only user %s can delete this entry"), owner); show_error(str); return; } } /* header */ if (message_id) sprintf(str, "%d", message_id); else str[0] = 0; show_standard_header(lbs, TRUE, "Delete ELog entry", str); rsprintf(""); rsprintf("\n", loc("Are you sure to delete these messages?")); rsprintf("\n"); if (reply) rsprintf("\n", loc("and all their replies")); } else { rsprintf("%s\n", loc("Are you sure to delete this entry?")); /* check for replies */ /* retrieve original message */ el_retrieve(lbs, message_id, NULL, attr_list, NULL, 0, NULL, NULL, in_reply_to, reply_to, NULL, NULL, NULL); if (reply_to[0]) rsprintf("\n", message_id, loc("and all its replies")); else rsprintf("\n", message_id); /* put link to next message */ next = el_search_message(lbs, EL_NEXT, message_id, TRUE); rsprintf("\n", next); } rsprintf ("\n\n"); } rsprintf("
\n"); /* define hidden field for command */ rsprintf("\n", loc("Delete")); if (!message_id) { rsprintf("%s
\n"); rsprintf("\n", getparam("nsel")); if (isparam("lastcmd")) { strcpy(str, getparam("lastcmd")); rsprintf("\n", str); } for (i = reply = 0; i < atoi(getparam("nsel")); i++) { sprintf(str, "s%d", i); if (isparam(str)) { rsprintf("#%s ", getparam(str)); rsprintf("\n", str, getparam(str)); } if (!reply) { el_retrieve(lbs, atoi(getparam(str)), NULL, attr_list, NULL, 0, NULL, NULL, in_reply_to, reply_to, NULL, NULL, NULL); if (reply_to[0]) reply = TRUE; } } rsprintf("
%s
#%d
%s
#%d
\n", loc("Yes")); rsprintf("\n", loc("No")); rsprintf("
\n"); show_bottom_text(lbs); rsprintf("\r\n"); } /*------------------------------------------------------------------*/ int show_download_page(LOGBOOK * lbs, char *path) { char file_name[256], error_str[256]; int index, message_id, fh, i, size, delta; char message[TEXT_SIZE + 1000], *p, *buffer; message_id = atoi(path); if (message_id == 0) { /* return config */ load_config_section(lbs->name, &buffer, error_str); if (error_str[0]) { rsprintf("Error loading configuration file: %s", error_str); return EL_FILE_ERROR; } size = strlen(buffer); strlcpy(message, buffer, sizeof(message)); free(buffer); } else { /* return entry */ for (index = 0; index < *lbs->n_el_index; index++) if (lbs->el_index[index].message_id == message_id) break; if (index == *lbs->n_el_index) return EL_NO_MSG; sprintf(file_name, "%s%s", lbs->data_dir, lbs->el_index[index].file_name); fh = open(file_name, O_RDWR | O_BINARY, 0644); if (fh < 0) return EL_FILE_ERROR; lseek(fh, lbs->el_index[index].offset, SEEK_SET); i = read(fh, message, sizeof(message) - 1); if (i <= 0) { close(fh); return EL_FILE_ERROR; } message[i] = 0; close(fh); /* decode message size */ p = strstr(message + 8, "$@MID@$:"); if (p == NULL) size = strlen(message); else size = (int) p - (int) message; message[size] = 0; } show_plain_header(size, "export.txt"); /* increase return buffer size if file too big */ if (size > return_buffer_size - (int) strlen(return_buffer)) { delta = size - (return_buffer_size - strlen(return_buffer)) + 1000; return_buffer = realloc(return_buffer, return_buffer_size + delta); memset(return_buffer + return_buffer_size, 0, delta); return_buffer_size += delta; } return_length = strlen(return_buffer) + size; strlcat(return_buffer, message, return_buffer_size); return EL_SUCCESS; } /*------------------------------------------------------------------*/ void show_import_page(LOGBOOK * lbs) { char str[256], str2[256]; /*---- header ----*/ show_html_header(lbs, FALSE, loc("ELOG CSV import"), TRUE); rsprintf ("\n"); /*---- title ----*/ show_standard_title(lbs->name, "", 0); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n", loc("Cancel")); rsprintf("\n", loc("Import")); rsprintf("\n\n"); /* table for two-column items */ rsprintf(""); rsprintf("\n"); /*---- entry form ----*/ rsprintf("\n", loc("Field separator")); rsprintf("\n"); rsprintf("\n", loc("Options")); rsprintf("\n"); rsprintf("\n", loc("CSV filename")); rsprintf("\n"); rsprintf("
%s:"); str[0] = 0; if (isparam("sep")) strcpy(str, getparam("sep")); if (str[0] == 0) rsprintf(""); else rsprintf(""); rsprintf("\n", loc("Auto detect")); if (str[0] == ',') rsprintf(""); else rsprintf(""); rsprintf("\n", loc("Comma")); if (str[0] == ';') rsprintf(""); else rsprintf(""); rsprintf("\n", loc("Semicolon")); rsprintf("
%s:"); if (isparam("head")) rsprintf("\n"); else rsprintf("\n"); rsprintf("
\n", loc("Derive attributes from CSV file")); if (isparam("ignore")) rsprintf ("\n"); else rsprintf("\n"); rsprintf("
\n", loc("Ignore first line")); rsprintf("\n"); rsprintf("
\n", loc("Preview import")); if (isparam("filltext")) rsprintf ("\n"); else rsprintf("\n"); strcpy(str, loc("text")); sprintf(str2, loc("Column header '%s' must be present in CSV file"), str); rsprintf("
\n", loc("Fill text body"), str2); rsprintf("
%s:"); if (isparam("csvfile")) rsprintf("%s:
\n", loc("Please re-enter filename")); rsprintf("
\n\n"); show_bottom_text(lbs); rsprintf("
\r\n"); } /*------------------------------------------------------------------*/ void csv_import(LOGBOOK * lbs, char *csv, char *csvfile) { char *list, *line, *p, str[256], date[80], sep[80]; int i, j, n, n_attr, iline, n_imported, textcol; BOOL first, in_quotes, filltext; list = malloc(MAX_N_ATTR * NAME_LENGTH); if (list == NULL) return; line = malloc(10000); if (line == NULL) { free(list); return; } first = TRUE; in_quotes = FALSE; iline = n_imported = 0; filltext = FALSE; textcol = -1; strcpy(sep, ","); if (isparam("sep")) strcpy(sep, getparam("sep")); if (sep[0] == 0) strcpy(sep, ","); if (strieq(sep, "auto")) { /* count commas */ for (i = 0, p = csv; p; i++) { p = strchr(p, ','); if (p) p++; } n = i; /* count semicolon */ for (i = 0, p = csv; p; i++) { p = strchr(p, ';'); if (p) p++; } strcpy(sep, i > n ? ";" : ","); } n_attr = lbs->n_attr; if (isparam("preview")) { /* title row */ sprintf(str, loc("CSV import preview of %s"), csvfile); show_standard_header(lbs, TRUE, str, "./"); rsprintf("\n"); rsprintf("\n", str, str); /* menu buttons */ rsprintf("\n\n"); rsprintf("
%s
\n"); rsprintf("\n", loc("Cancel")); rsprintf("\n", loc("CSV Import")); /* hidden fields */ rsprintf("\n", sep); if (isparam("head")) rsprintf("\n", getparam("head")); if (isparam("ignore")) rsprintf("\n", getparam("ignore")); if (isparam("filltext")) rsprintf("\n", getparam("filltext")); rsprintf("\n", csvfile); rsprintf("
"); } p = csv; do { for (i = 0; i < 10000 && *p; i++) { if (!in_quotes && (*p == '\r' || *p == '\n')) break; line[i] = *p++; if (line[i] == '"') in_quotes = !in_quotes; } line[i] = 0; while (*p == '\r' || *p == '\n') p++; if (!*p) break; memset(list, 0, MAX_N_ATTR * NAME_LENGTH); n = strbreak(line, (char (*)[NAME_LENGTH]) list, MAX_N_ATTR, sep); if (n == MAX_N_ATTR) { sprintf(str, loc("Too many attributes in CSV file")); show_error(str); } /* ignore first line */ if (first && isparam("ignore")) { first = FALSE; continue; } /* check if text column is present */ if (first && atoi(getparam("filltext"))) { for (i = 0; i < n; i++) if (strieq(list + i * NAME_LENGTH, loc("text"))) { filltext = TRUE; textcol = i; break; } } /* derive attributes from first line */ if (first && isparam("head")) { if (isparam("preview")) { rsprintf("\n"); for (i = 0; i < n; i++) if (i != textcol) rsprintf("\n", list + i * NAME_LENGTH); if (filltext) rsprintf("\n", loc("text")); rsprintf("\n"); if (filltext) n_attr = n - 1; else n_attr = n; } else { for (i = j = 0; i < n; i++) if (i != textcol) strlcpy(attr_list[j++], list + i * NAME_LENGTH, NAME_LENGTH); if (filltext) { if (!set_attributes(lbs, attr_list, n - 1)) return; lbs->n_attr = n - 1; } else { if (!set_attributes(lbs, attr_list, n)) return; lbs->n_attr = n; } } } else { if (isparam("preview")) { rsprintf("\n"); for (i = j = 0; i < n_attr; i++) { if (iline % 2 == 0) rsputs("\n"); j++; } if (filltext) { rsputs("\n"); } rsputs("\n"); iline++; } else { if (!filltext) { /* submit entry */ date[0] = 0; if (el_submit(lbs, 0, FALSE, date, attr_list, (char (*)[NAME_LENGTH]) list, n_attr, "", "", "", "plain", NULL, TRUE, NULL)) n_imported++; } else { strlcpy(line, list + textcol * NAME_LENGTH, 10000); insert_breaks(line, 78, 10000); for (i = textcol; i < n_attr; i++) strlcpy(list + i * NAME_LENGTH, list + (i + 1) * NAME_LENGTH, NAME_LENGTH); /* submit entry */ date[0] = 0; if (el_submit(lbs, 0, FALSE, date, attr_list, (char (*)[NAME_LENGTH]) list, n_attr, line, "", "", "plain", NULL, TRUE, NULL)) n_imported++; } } } first = FALSE; } while (*p); free(line); free(list); if (isparam("preview")) { rsprintf("
%s%s
"); else rsputs(""); /* skip text column */ if (i == textcol) j++; if (i >= n || !list[j * NAME_LENGTH]) rsputs(" "); else rsputs(list + j * NAME_LENGTH); rsputs(""); if (list[textcol * NAME_LENGTH]) rsputs(list + textcol * NAME_LENGTH); else rsputs(" "); rsputs("
\n"); show_bottom_text(lbs); rsprintf("\r\n"); return; } sprintf(str, loc("%d entries successfully imported"), n_imported); show_elog_list(lbs, 0, 0, 1, str); } /*------------------------------------------------------------------*/ int show_md5_page(LOGBOOK * lbs) { int i, j; char *buffer, error_str[256]; unsigned char digest[16]; /* header */ rsprintf("HTTP/1.1 200 Document follows\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); rsprintf("Accept-Ranges: bytes\r\n"); rsprintf("Connection: close\r\n"); rsprintf("Content-Type: text/plain;charset=iso-8859-1\r\n"); rsprintf("Pragma: no-cache\r\n"); rsprintf("Expires: Fri, 01 Jan 1983 00:00:00 GMT\r\n\r\n"); /* calculate MD5 for logbook section in config file */ load_config_section(lbs->name, &buffer, error_str); if (error_str[0]) rsprintf("Error loading configuration file: %s", error_str); else { rsprintf("ID: %6d MD5:", 0); remove_crlf(buffer); MD5_checksum(buffer, strlen(buffer), digest); for (i = 0; i < 16; i++) rsprintf("%02X", digest[i]); rsprintf("\n"); } free(buffer); /* show MD5's of logbook entries */ for (i = 0; i < *lbs->n_el_index; i++) { rsprintf("ID: %6d MD5:", lbs->el_index[i].message_id); for (j = 0; j < 16; j++) rsprintf("%02X", lbs->el_index[i].md5_digest[j]); rsprintf("\n"); } keep_alive = 0; return EL_SUCCESS; } /*------------------------------------------------------------------*/ void combine_url(LOGBOOK * lbs, char *url, char *param, char *result, int size) { if (strstr(url, "http://")) strlcpy(result, url + 7, size); else strlcpy(result, url, size); url_encode(result, size); if (result[strlen(result) - 1] != '/') strlcat(result, "/", size); if (!strstr(result, lbs->name_enc)) { strlcat(result, lbs->name_enc, size); strlcat(result, "/", size); } if (param) strlcat(result, param, size); } /*------------------------------------------------------------------*/ int retrieve_remote_md5(LOGBOOK * lbs, char *host, MD5_INDEX ** md5_index, char *error_str) { int i, n, id, x, version; char *text, *p, url[256], str[256]; *md5_index = NULL; combine_url(lbs, host, "?cmd=GetMD5", url, sizeof(url)); text = NULL; error_str[0] = 0; if (retrieve_url(url, &text) < 0) { sprintf(error_str, loc("Cannot connect to remote server \"%s\""), host); return -1; } p = strstr(text, "ELOG HTTP "); if (!p) { if (isparam("debug")) rsputs(text); sprintf(error_str, loc("Remote server is not an ELOG server")); free(text); return -1; } version = atoi(p + 10) * 100 + atoi(p + 12) * 10 + atoi(p + 14); if (version < 250) { if (isparam("debug")) rsputs(text); memset(str, 0, sizeof(str)); strncpy(str, p + 10, 5); sprintf(error_str, loc("Incorrect remote ELOG server version %s"), str); free(text); return -1; } p = strstr(text, "Location: "); if (p) { if (isparam("debug")) rsputs(text); if (strstr(text, "?wusr=")) sprintf(error_str, loc("User \"%s\" has no access to remote logbook"), getparam("unm")); else if (strstr(text, "?wpwd=")) sprintf(error_str, loc("Passwords for user \"%s\" do not match locally and remotely"), getparam("unm")); else sprintf(error_str, loc("Error accessing remote logbook")); return -1; } p = strstr(text, "\r\n\r\n"); if (!p) { if (isparam("debug")) rsputs(text); sprintf(error_str, loc("Invalid HTTP header")); free(text); return -1; } for (n = 0;; n++) { p = strstr(p, "ID:"); if (!p) break; p += 3; id = atoi(p); p = strstr(p, "MD5:"); if (!p) break; p += 4; if (n == 0) *md5_index = malloc(sizeof(MD5_INDEX)); else *md5_index = realloc(*md5_index, (n + 1) * sizeof(MD5_INDEX)); (*md5_index)[n].message_id = id; for (i = 0; i < 16; i++) { sscanf(p + 2 * i, "%02X", &x); (*md5_index)[n].md5_digest[i] = (unsigned char) x; } } if (n == 0) { if (isparam("debug")) rsputs(text); if (strstr(text, "Login")) sprintf(error_str, loc("No user name supplied to access remote logbook")); else sprintf(error_str, loc("Error accessing remote logbook")); } free(text); return n; } /*------------------------------------------------------------------*/ INT send_tcp(int sock, char *buffer, unsigned int buffer_size, INT flags) /********************************************************************\ Send network data over TCP port. Break buffer in smaller parts if larger than maximum TCP buffer size (usually 64k). \********************************************************************/ { #ifndef NET_TCP_SIZE #define NET_TCP_SIZE 65536 #endif unsigned int count; int status; /* transfer fragments until complete buffer is transferred */ for (count = 0; count < buffer_size - NET_TCP_SIZE;) { status = send(sock, buffer + count, NET_TCP_SIZE, flags); if (status != -1) count += status; else { return status; } } while (count < buffer_size) { status = send(sock, buffer + count, buffer_size - count, flags); if (status != -1) count += status; else { return status; } } return count; } /*------------------------------------------------------------------*/ int submit_message(LOGBOOK * lbs, char *host, int message_id, char *error_str) { int size, i, n, status, fh, port, sock, content_length, header_length, remote_id, n_attr; char str[256], file_name[MAX_PATH_LENGTH], attrib[MAX_N_ATTR][NAME_LENGTH]; char host_name[256], subdir[256], param[256], local_host_name[256], url[256]; char date[80], *text, in_reply_to[80], reply_to[MAX_REPLY_TO * 10], attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], encoding[80], locked_by[256], *buffer; char *content, *p, boundary[80], request[10000], response[10000]; struct hostent *phe; struct sockaddr_in bind_addr; text = malloc(TEXT_SIZE); error_str[0] = 0; /* get message with attribute list devied from database */ size = TEXT_SIZE; status = el_retrieve(lbs, message_id, date, attr_list, attrib, -1, text, &size, in_reply_to, reply_to, attachment, encoding, locked_by); if (status != EL_SUCCESS) { free(text); strcpy(error_str, loc("Cannot read entry from local logbook")); return -1; } /* count attributes */ for (n_attr = 0; attr_list[n_attr][0]; n_attr++); combine_url(lbs, host, "", url, sizeof(url)); split_url(url, host_name, &port, subdir, param); /* create socket */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { free(text); strcpy(error_str, loc("Cannot create socket")); return -1; } /* get local host name */ gethostname(local_host_name, sizeof(local_host_name)); /* compose remote address */ memset(&bind_addr, 0, sizeof(bind_addr)); bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = 0; bind_addr.sin_port = htons((unsigned short) port); phe = gethostbyname(host_name); if (phe == NULL) { closesocket(sock); free(text); sprintf(error_str, loc("Cannot resolve host name \"%s\""), host_name); return -1; } memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length); /* connect to server */ status = connect(sock, (void *) &bind_addr, sizeof(bind_addr)); if (status != 0) { closesocket(sock); free(text); sprintf(error_str, loc("Cannot connect to host %s, port %d"), host_name, port); return -1; } content_length = 100000; for (i = 0; i < MAX_ATTACHMENTS; i++) if (attachment[i][0]) { strlcpy(file_name, lbs->data_dir, sizeof(file_name)); strlcat(file_name, attachment[i], sizeof(file_name)); fh = open(file_name, O_RDONLY | O_BINARY); if (fh > 0) { lseek(fh, 0, SEEK_END); size = TELL(fh); close(fh); } else size = 0; content_length += size; } content = malloc(content_length); if (content == NULL) { closesocket(sock); free(text); strcpy(error_str, loc("Not enough memory")); return -1; } /* compose content */ srand((unsigned) time(NULL)); sprintf(boundary, "---------------------------%04X%04X%04X", rand(), rand(), rand()); strcpy(content, boundary); strcat(content, "\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nSubmit\r\n"); sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"mirror_id\"\r\n\r\n%d\r\n", boundary, message_id); if (isparam("unm")) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"unm\"\r\n\r\n%s\r\n", boundary, getparam("unm")); if (isparam("upwd")) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"upwd\"\r\n\r\n%s\r\n", boundary, getparam("upwd")); if (in_reply_to[0]) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"in_reply_to\"\r\n\r\n%s\r\n", boundary, in_reply_to); if (reply_to[0]) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"reply_to\"\r\n\r\n%s\r\n", boundary, reply_to); for (i = 0; i < n_attr; i++) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", boundary, attr_list[i], attrib[i]); sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"entry_date\"\r\n\r\n%s\r\n", boundary, date); sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"encoding\"\r\n\r\n%s\r\n", boundary, encoding); sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"Text\"\r\n\r\n%s\r\n%s\r\n", boundary, text, boundary); content_length = strlen(content); p = content + content_length; /* read attachments */ for (i = 0; i < MAX_ATTACHMENTS; i++) if (attachment[i][0]) { strlcpy(file_name, lbs->data_dir, sizeof(file_name)); strlcat(file_name, attachment[i], sizeof(file_name)); fh = open(file_name, O_RDONLY | O_BINARY); if (fh > 0) { lseek(fh, 0, SEEK_END); size = TELL(fh); lseek(fh, 0, SEEK_SET); buffer = malloc(size); if (buffer == NULL) { closesocket(sock); free(text); strcpy(error_str, loc("Not enough memory")); return -1; } read(fh, buffer, size); close(fh); /* submit attachment */ sprintf(p, "Content-Disposition: form-data; name=\"attfile%d\"; filename=\"%s\"\r\n\r\n", i + 1, attachment[i]); content_length += strlen(p); p += strlen(p); memcpy(p, buffer, size); p += size; strcpy(p, boundary); strcat(p, "\r\n"); content_length += size + strlen(p); p += strlen(p); free(buffer); } } /* compose request */ strcpy(request, "POST "); if (subdir[0]) { if (subdir[0] != '/') strcat(request, "/"); strcat(request, subdir); if (request[strlen(request) - 1] != '/') strcat(request, "/"); } strcat(request, " HTTP/1.0\r\n"); sprintf(request + strlen(request), "Content-Type: multipart/form-data; boundary=%s\r\n", boundary); sprintf(request + strlen(request), "Host: %s\r\n", local_host_name); sprintf(request + strlen(request), "User-Agent: ELOGD\r\n"); sprintf(request + strlen(request), "Content-Length: %d\r\n", content_length); if (isparam("wpwd")) sprintf(request + strlen(request), "Cookie: wpwd=%s\r\n", getparam("wpwd")); strcat(request, "\r\n"); header_length = strlen(request); /* send request */ send(sock, request, header_length, 0); /* send content */ send_tcp(sock, content, content_length, 0); /* receive response */ i = recv(sock, response, 10000, 0); if (i < 0) { closesocket(sock); free(text); strcpy(error_str, "Cannot receive response"); return -1; } /* discard remainder of response */ n = i; while (i > 0) { i = recv(sock, response + n, 10000, 0); if (i > 0) n += i; } response[n] = 0; closesocket(sock); remote_id = -1; /* check response status */ if (strstr(response, "302 Found")) { if (strstr(response, "Location:")) { if (strstr(response, "wpwd")) sprintf(error_str, "Invalid password\n"); else if (strstr(response, "wusr")) sprintf(error_str, "Invalid user name\n"); strlcpy(str, strstr(response, "Location:") + 9, sizeof(str)); if (strchr(str, '\n')) *strchr(str, '\n') = 0; if (strchr(str, '?')) *strchr(str, '?') = 0; if (strrchr(str, '/')) remote_id = atoi(strrchr(str, '/') + 1); else remote_id = atoi(str); } } else if (strstr(response, "Logbook Selection")) sprintf(error_str, "No logbook specified\n"); else if (strstr(response, "enter password")) sprintf(error_str, "Missing or invalid password\n"); else if (strstr(response, "form name=form1")) sprintf(error_str, "Missing or invalid user name/password\n"); else if (strstr(response, "Error: Attribute")) { strncpy(str, strstr(response, "Error: Attribute") + 20, sizeof(str)); if (strchr(str, '<')) *strchr(str, '<') = 0; sprintf(error_str, "Missing required attribute \"%s\"\n", str); } else sprintf(error_str, "Error transmitting message\n"); if (error_str[0] && isparam("debug")) rsputs(text); free(text); if (error_str[0]) return -1; return remote_id; } /*------------------------------------------------------------------*/ int receive_message(LOGBOOK * lbs, char *url, int message_id, char *error_str, BOOL bnew) { int i, status, size, n_attr; char str[NAME_LENGTH], str2[NAME_LENGTH], *p, *p2, *message, date[80], attrib[MAX_N_ATTR][NAME_LENGTH], in_reply_to[80], reply_to[MAX_REPLY_TO * 10], encoding[80], locked_by[256], attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], attachment_all[64 * MAX_ATTACHMENTS]; error_str[0] = 0; combine_url(lbs, url, "", str, sizeof(str)); sprintf(str + strlen(str), "%d?cmd=%s", message_id, loc("Download")); retrieve_url(str, &message); p = strstr(message, "\r\n\r\n"); if (p == NULL) { if (isparam("debug")) rsputs(message); free(message); sprintf(error_str, loc("Cannot receive \"%s\""), str); return -1; } p += 4; /* check for correct ID */ if (atoi(p + 8) != message_id) { if (isparam("debug")) rsputs(message); free(message); sprintf(error_str, loc("Received wrong entry id \"%d\""), atoi(p + 8)); return -1; } /* decode entry */ el_decode(p, "Date: ", date); el_decode(p, "Reply to: ", reply_to); el_decode(p, "In reply to: ", in_reply_to); /* derive attribute names from message */ for (i = 0;; i++) { el_enum_attr(p, i, attr_list[i], attrib[i]); if (!attr_list[i][0]) break; } n_attr = i; el_decode(p, "Attachment: ", attachment_all); el_decode(p, "Encoding: ", encoding); /* break apart attachements */ for (i = 0; i < MAX_ATTACHMENTS; i++) attachment[i][0] = 0; for (i = 0; i < MAX_ATTACHMENTS; i++) { if (i == 0) p2 = strtok(attachment_all, ","); else p2 = strtok(NULL, ","); if (p2 != NULL) strcpy(attachment[i], p2); else break; } el_decode(p, "Locked by: ", locked_by); if (locked_by[0]) { free(message); sprintf(error_str, loc("Entry #%d is locked on remote server"), message_id); return -1; } p = strstr(message, "========================================\n"); /* check for \n -> \r conversion (e.g. zipping/unzipping) */ if (p == NULL) p = strstr(message, "========================================\r"); if (p != NULL) { p += 41; /* remove last CR */ if (p[strlen(p) - 1] == '\n') p[strlen(p) - 1] = 0; status = el_submit(lbs, message_id, !bnew, date, attr_list, attrib, n_attr, p, in_reply_to, reply_to, encoding, attachment, FALSE, ""); free(message); if (status != message_id) { sprintf(error_str, loc("Cannot save remote entry locally")); return -1; } for (i = 0; i < MAX_ATTACHMENTS; i++) { if (attachment[i][0]) { combine_url(lbs, url, "", str, sizeof(str)); strlcpy(str2, attachment[i], sizeof(str2)); str2[13] = '/'; strlcat(str, str2, sizeof(str)); size = retrieve_url(str, &message); p = strstr(message, "\r\n\r\n"); if (p == NULL) { free(message); sprintf(error_str, loc("Cannot receive \"%s\""), str); return -1; } p += 4; el_submit_attachment(lbs, attachment[i], p, size, NULL); free(message); } } } else { free(message); return -1; } return 1; } /*------------------------------------------------------------------*/ void submit_config(LOGBOOK * lbs, char *server, char *buffer, char *error_str) { int i, n, status, port, sock, content_length, header_length; char str[256]; char host_name[256], subdir[256], param[256], local_host_name[256]; char *content, *p, boundary[80], request[10000], response[10000]; struct hostent *phe; struct sockaddr_in bind_addr; error_str[0] = 0; combine_url(lbs, server, "", str, sizeof(str)); split_url(str, host_name, &port, subdir, param); /* create socket */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { strcpy(error_str, loc("Cannot create socket")); return; } /* get local host name */ gethostname(local_host_name, sizeof(local_host_name)); /* compose remote address */ memset(&bind_addr, 0, sizeof(bind_addr)); bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = 0; bind_addr.sin_port = htons((unsigned short) port); phe = gethostbyname(host_name); if (phe == NULL) { closesocket(sock); sprintf(error_str, loc("Cannot resolve host name \"%s\""), host_name); return; } memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length); /* connect to server */ status = connect(sock, (void *) &bind_addr, sizeof(bind_addr)); if (status != 0) { closesocket(sock); sprintf(error_str, loc("Cannot connect to host %s, port %d"), host_name, port); return; } content_length = 100000; content = malloc(content_length); if (content == NULL) { closesocket(sock); strcpy(error_str, loc("Not enough memory")); return; } /* compose content */ srand((unsigned) time(NULL)); sprintf(boundary, "---------------------------%04X%04X%04X", rand(), rand(), rand()); strcpy(content, boundary); strcat(content, "\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nSave\r\n"); if (isparam("unm")) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"unm\"\r\n\r\n%s\r\n", boundary, getparam("unm")); if (isparam("upwd")) sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"upwd\"\r\n\r\n%s\r\n", boundary, getparam("upwd")); sprintf(content + strlen(content), "%s\r\nContent-Disposition: form-data; name=\"Text\"\r\n\r\n%s\r\n%s\r\n", boundary, buffer, boundary); content_length = strlen(content); p = content + content_length; /* compose request */ strcpy(request, "POST "); if (subdir[0]) { if (subdir[0] != '/') strcat(request, "/"); strcat(request, subdir); if (request[strlen(request) - 1] != '/') strcat(request, "/"); } strcat(request, " HTTP/1.0\r\n"); sprintf(request + strlen(request), "Content-Type: multipart/form-data; boundary=%s\r\n", boundary); sprintf(request + strlen(request), "Host: %s\r\n", local_host_name); sprintf(request + strlen(request), "User-Agent: ELOGD\r\n"); sprintf(request + strlen(request), "Content-Length: %d\r\n", content_length); if (isparam("wpwd")) sprintf(request + strlen(request), "Cookie: wpwd=%s\r\n", getparam("wpwd")); strcat(request, "\r\n"); header_length = strlen(request); /* send request */ send(sock, request, header_length, 0); /* send content */ send(sock, content, content_length, 0); /* receive response */ i = recv(sock, response, 10000, 0); if (i < 0) { closesocket(sock); strcpy(error_str, "Cannot receive response"); return; } /* discard remainder of response */ n = i; while (i > 0) { i = recv(sock, response + n, 10000, 0); if (i > 0) n += i; } response[n] = 0; closesocket(sock); /* check response status */ if (strstr(response, "302 Found")) { if (strstr(response, "Location:")) { if (strstr(response, "wpwd")) sprintf(error_str, "Invalid password\n"); else if (strstr(response, "wusr")) sprintf(error_str, "Invalid user name\n"); } } else if (strstr(response, "Logbook Selection")) sprintf(error_str, "No logbook specified\n"); else if (strstr(response, "enter password")) sprintf(error_str, "Missing or invalid password\n"); else if (strstr(response, "form name=form1")) sprintf(error_str, "Missing or invalid user name/password\n"); else if (strstr(response, "Error: Attribute")) { strncpy(str, strstr(response, "Error: Attribute") + 20, sizeof(str)); if (strchr(str, '<')) *strchr(str, '<') = 0; sprintf(error_str, "Missing required attribute \"%s\"\n", str); } else sprintf(error_str, "Error transmitting message\n"); } /*------------------------------------------------------------------*/ void receive_config(LOGBOOK * lbs, char *server, char *error_str) { char str[256], *buffer, *p; error_str[0] = 0; combine_url(lbs, server, "", str, sizeof(str)); sprintf(str + strlen(str), "?cmd=Download"); retrieve_url(str, &buffer); p = strstr(buffer, "\r\n\r\n"); if (p == NULL) { free(buffer); sprintf(error_str, loc("Cannot receive \"%s\""), str); return; } p += 4; if (!save_admin_config(lbs->name, p, str)) rsprintf(str); free(buffer); } /*------------------------------------------------------------------*/ int save_md5(LOGBOOK * lbs, char *server, MD5_INDEX * md5_index, int n) { char str[256], url[256], file_name[256]; int i, j; FILE *f; combine_url(lbs, server, "", url, sizeof(url)); url_decode(url); if (strstr(url, "http://")) strcpy(str, url + 7); else strcpy(str, url); for (i = 0; i < (int) strlen(str); i++) if (strchr(":/\\ ", str[i])) str[i] = '_'; while (str[strlen(str) - 1] == '_') str[strlen(str) - 1] = 0; strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); strlcat(file_name, ".md5", sizeof(file_name)); f = fopen(file_name, "wt"); if (f == NULL) return -1; for (i = 0; i < n; i++) { fprintf(f, "ID%d: ", md5_index[i].message_id); for (j = 0; j < 16; j++) fprintf(f, "%02X", md5_index[i].md5_digest[j]); fprintf(f, "\n"); } fclose(f); return 1; } /*------------------------------------------------------------------*/ int load_md5(LOGBOOK * lbs, char *server, MD5_INDEX ** md5_index) { char str[256], url[256], file_name[256], *p; int i, j, x; FILE *f; *md5_index = NULL; combine_url(lbs, server, "", url, sizeof(url)); url_decode(url); if (strstr(url, "http://")) strcpy(str, url + 7); else strcpy(str, url); for (i = 0; i < (int) strlen(str); i++) if (strchr(":/\\ ", str[i])) str[i] = '_'; while (str[strlen(str) - 1] == '_') str[strlen(str) - 1] = 0; strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); strlcat(file_name, ".md5", sizeof(file_name)); f = fopen(file_name, "rt"); if (f == NULL) return 0; for (i = 0; !feof(f); i++) { str[0] = 0; fgets(str, sizeof(str), f); if (!str[0]) break; if (i == 0) *md5_index = calloc(sizeof(MD5_INDEX), 1); else *md5_index = realloc(*md5_index, sizeof(MD5_INDEX) * (i + 1)); p = str + 2; (*md5_index)[i].message_id = atoi(p); while (*p && *p != ' ') p++; while (*p && *p == ' ') p++; for (j = 0; j < 16; j++) { sscanf(p + j * 2, "%02X", &x); (*md5_index)[i].md5_digest[j] = (unsigned char) x; } } fclose(f); return i; } /*------------------------------------------------------------------*/ BOOL equal_md5(unsigned char m1[16], unsigned char m2[16]) { int i; for (i = 0; i < 16; i++) if (m1[i] != m2[i]) break; return i == 16; } /*------------------------------------------------------------------*/ void synchronize_logbook(LOGBOOK * lbs, BOOL bcron) { int index, i, j, i_msg, i_remote, i_cache, n_remote, n_cache, nserver, remote_id, exist_remote, exist_cache, message_id, max_id; int all_identical; char str[2000], url[256], loc_ref[256], rem_ref[256]; MD5_INDEX *md5_remote, *md5_cache; char list[MAX_N_LIST][NAME_LENGTH], error_str[256], *buffer; unsigned char digest[16]; if (!getcfg(lbs->name, "Mirror server", str)) { show_error(loc("No mirror server defined in configuration file")); return; } nserver = strbreak(str, list, MAX_N_LIST, ","); for (index = 0; index < nserver; index++) { if (!bcron) { rsprintf("%s", lbs->name_enc, lbs->name); else sprintf(loc_ref, "%s", lbs->name_enc, lbs->name); sprintf(str, loc("Synchronizing logbook %s with server \"%s\""), loc_ref, list[index]); rsprintf("\n", str); rsprintf("
%s

\n"); rsprintf("

");
      }

      /* send partial return buffer */
      flush_return_buffer();

      n_remote = retrieve_remote_md5(lbs, list[index], &md5_remote, error_str);
      if (n_remote <= 0) {

         if (bcron)
            logf(lbs, error_str);
         else
            rsprintf("%s\n", error_str);

         if (md5_remote)
            free(md5_remote);

         if (!bcron)
            rsprintf("
\n"); continue; } /* load local copy of remote MD5s from file */ n_cache = load_md5(lbs, list[index], &md5_cache); /*---- check for configuration file ----*/ if (getcfg(lbs->name, "Mirror config", str) && atoi(str) == 1 && md5_cache) { load_config_section(lbs->name, &buffer, error_str); if (error_str[0]) { if (bcron) logf(lbs, "Error loading configuration file: %s", error_str); else rsprintf("Error loading configuration file: %s\n", error_str); } else { remove_crlf(buffer); MD5_checksum(buffer, strlen(buffer), digest); } /* compare MD5s */ /* printf("ID0: "); for (j = 0; j < 16; j++) printf("%02X", digest[j]); printf("\nCache : "); for (j = 0; j < 16; j++) printf("%02X", md5_cache[0].md5_digest[j]); printf("\nRemote: "); for (j = 0; j < 16; j++) printf("%02X", md5_remote[0].md5_digest[j]); printf("\n\n"); */ if (n_remote > 0) { /* if config has been changed on this server, but not remotely, send it */ if (!equal_md5(md5_cache[0].md5_digest, digest) && equal_md5(md5_cache[0].md5_digest, md5_remote[0].md5_digest)) { if (_logging_level > 1) logf(lbs, "MIRROR send config"); /* submit configuration section */ if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) submit_config(lbs, list[index], buffer, error_str); if (error_str[0]) { if (bcron) logf(lbs, "Error sending config file: %s", error_str); else rsprintf("Error sending config file: %s\n", error_str); } else { if (!bcron) rsprintf("Local config submitted\n"); } md5_cache[0].message_id = -1; } else /* if config has been changed remotely, but not on this server, receive it */ if (!equal_md5(md5_cache[0].md5_digest, md5_remote[0].md5_digest) && equal_md5(md5_cache[0].md5_digest, digest)) { if (_logging_level > 1) logf(lbs, "MIRROR receive config"); if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) receive_config(lbs, list[index], error_str); if (error_str[0]) { if (bcron) logf(lbs, "Error receiving config file: %s\n", error_str); else rsprintf("Error receiving config file: %s\n", error_str); } else { if (!bcron) rsprintf("Remote config received\n"); } md5_cache[0].message_id = -1; } else /* if config has been changed remotely and on this server, show conflict */ if (!equal_md5(md5_cache[0].md5_digest, md5_remote[0].md5_digest) && !equal_md5(md5_cache[0].md5_digest, digest) && !equal_md5(md5_remote[0].md5_digest, digest)) { if (_logging_level > 1) logf(lbs, "MIRROR config conflict"); if (!bcron) { rsprintf("%s.\n", loc("Configuration has been changed locally and remotely")); rsprintf(loc("Please merge manually to resolve conflict")); rsprintf(".\n"); } } else { /* configs are identical */ md5_cache[0].message_id = -1; } } else { /* n_remote == 0 */ sprintf(str, loc("Logbook \"%s\" does not exist on remote server"), lbs->name); if (bcron) logf(lbs, str); rsprintf("%s\n", str); continue; } flush_return_buffer(); if (buffer) free(buffer); } /*---- loop through logbook entries ----*/ all_identical = TRUE; for (i_msg = 0; i_msg < *lbs->n_el_index; i_msg++) { message_id = lbs->el_index[i_msg].message_id; /* look for message id in MD5s */ for (i_remote = 0; i_remote < n_remote; i_remote++) if (md5_remote[i_remote].message_id == message_id) break; exist_remote = i_remote < n_remote; for (i_cache = 0; i_cache < n_cache; i_cache++) if (md5_cache[i_cache].message_id == message_id) break; exist_cache = i_cache < n_cache; /* if message exists in both lists, compare MD5s */ if (exist_remote && exist_cache) { /* if message has been changed on this server, but not remotely, send it */ if (!equal_md5(md5_cache[i_cache].md5_digest, lbs->el_index[i_msg].md5_digest) && equal_md5(md5_cache[i_cache].md5_digest, md5_remote[i_remote].md5_digest)) { if (_logging_level > 1) logf(lbs, "MIRROR send entry #%d", message_id); /* submit local message */ if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) submit_message(lbs, list[index], message_id, error_str); all_identical = FALSE; /* not that submit_message() may have changed attr_list !!! */ if (error_str[0]) { if (bcron) logf(lbs, "Error sending local message: %s", error_str); else rsprintf("%s: %s\n", loc("Error sending local message"), error_str); } else if (!bcron) rsprintf("ID%d:\t%s\n", message_id, loc("Local entry submitted")); md5_cache[i_cache].message_id = -1; } else /* if message has been changed remotely, but not on this server, receive it */ if (!equal_md5 (md5_cache[i_cache].md5_digest, md5_remote[i_remote].md5_digest) && equal_md5(md5_cache[i_cache].md5_digest, lbs->el_index[i_msg].md5_digest)) { if (_logging_level > 1) logf(lbs, "MIRROR receive entry #%d", message_id); if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) receive_message(lbs, list[index], message_id, error_str, FALSE); all_identical = FALSE; if (error_str[0]) { if (bcron) logf(lbs, "Error receiving message: %s", error_str); else rsprintf("%s: %s\n", loc("Error receiving message"), error_str); } else if (!bcron) { if (getcfg_topgroup()) rsprintf("ID%d:\t", lbs->name_enc, message_id, message_id); else rsprintf("ID%d:\t", lbs->name_enc, message_id, message_id); rsprintf("%s\n", loc("Remote entry received")); } md5_cache[i_cache].message_id = -1; } else /* if message has been changed remotely and on this server, show conflict */ if (!equal_md5 (md5_cache[i_cache].md5_digest, md5_remote[i_remote].md5_digest) && !equal_md5(md5_cache[i_cache].md5_digest, lbs->el_index[i_msg].md5_digest) && !equal_md5(md5_remote[i_remote].md5_digest, lbs->el_index[i_msg].md5_digest)) { if (_logging_level > 1) logf(lbs, "MIRROR conflict entry #%d", message_id); combine_url(lbs, list[index], "", str, sizeof(str)); if (getcfg_topgroup()) sprintf(loc_ref, "%s", lbs->name_enc, message_id, loc("local")); else sprintf(loc_ref, "%s", message_id, loc("local")); sprintf(rem_ref, "%s", str, message_id, loc("remote")); all_identical = FALSE; if (!bcron) { rsprintf("ID%d:\t%s.\n\t", message_id, loc("Entry has been changed locally and remotely")); rsprintf(loc("Please delete %s or %s entry to resolve conflict"), loc_ref, rem_ref); rsprintf(".\n"); } } else { /* messages are identical */ md5_cache[i_cache].message_id = -1; } } if (exist_cache && !exist_remote) { /* if message has been changed locally, send it */ if (!equal_md5(md5_cache[i_cache].md5_digest, lbs->el_index[i_msg].md5_digest)) { if (_logging_level > 1) logf(lbs, "MIRROR send entry #%d", message_id); /* submit local message */ if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) submit_message(lbs, list[index], message_id, error_str); all_identical = FALSE; /* not that submit_message() may have changed attr_list !!! */ if (error_str[0]) { if (bcron) logf(lbs, "Error sending local message: %s", error_str); else rsprintf("%s: %s\n", loc("Error sending local message"), error_str); } else if (!bcron) rsprintf("ID%d:\t%s\n", message_id, loc("Local entry submitted")); md5_cache[i_cache].message_id = -1; } else { /* if message exists only in cache, but not remotely, it must have been deleted remotely, so remove it locally */ if (_logging_level > 1) logf(lbs, "MIRROR delete local entry #%d", message_id); if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) el_delete_message(lbs, message_id, TRUE, NULL, TRUE, TRUE); all_identical = FALSE; if (!bcron) rsprintf("ID%d:\t%s\n", message_id, loc("Entry deleted locally")); /* message got deleted from local message list, so redo current index */ i_msg--; /* mark message non-conflicting */ md5_cache[i_cache].message_id = -1; } } /* if message does not exist in cache and remotely, it must be new, so send it */ if (!exist_cache && !exist_remote) { if (_logging_level > 1) logf(lbs, "MIRROR send entry #%d", message_id); remote_id = 0; if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) remote_id = submit_message(lbs, list[index], message_id, error_str); all_identical = FALSE; if (remote_id != message_id) { if (bcron) logf(lbs, "Error: Submitting entry #%d resulted in remote entry #%d\n", message_id, remote_id); else rsprintf("Error: Submitting entry #%d resulted in remote entry #%d\n", message_id, remote_id); } else if (error_str[0]) { if (bcron) logf(lbs, "%s: %s", loc("Error sending local entry"), error_str); else rsprintf("%s: %s\n", loc("Error sending local entry"), error_str); } else if (!bcron) rsprintf("ID%d:\t%s\n", message_id, loc("Local entry submitted")); } /* if message does not exist in cache but remotely, messages were added on both sides, so resubmit local one and retrieve remote one if messages are different */ if (!exist_cache && exist_remote && !equal_md5(md5_remote[i_remote].md5_digest, lbs->el_index[i_msg].md5_digest)) { /* find max id both locally and remotely */ max_id = 1; for (i = 0; i < *lbs->n_el_index; i++) if (lbs->el_index[i].message_id > max_id) max_id = lbs->el_index[i].message_id; for (i = 0; i < n_remote; i++) if (md5_remote[i].message_id > max_id) max_id = md5_remote[i].message_id; if (_logging_level > 1) logf(lbs, "MIRROR change entry #%d to #%d", message_id, max_id + 1); /* rearrange local message not to conflict with remote message */ if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) el_move_message(lbs, message_id, max_id + 1); all_identical = FALSE; if (!bcron) { sprintf(str, loc("Changed local entry ID to %d"), max_id + 1); rsprintf("ID%d:\t%s\n", message_id, str); } /* current message has been changed, so start over */ i_msg--; } flush_return_buffer(); } /* go through remote message which do not exist locally */ for (i_remote = 0; i_remote < n_remote; i_remote++) if (md5_remote[i_remote].message_id) { message_id = md5_remote[i_remote].message_id; for (i_msg = 0; i_msg < *lbs->n_el_index; i_msg++) if (message_id == lbs->el_index[i_msg].message_id) break; if (i_msg == *lbs->n_el_index) { for (i_cache = 0; i_cache < n_cache; i_cache++) if (md5_cache[i_cache].message_id == message_id) break; exist_cache = i_cache < n_cache; if (!exist_cache) { if (_logging_level > 1) logf(lbs, "MIRROR receive entry #%d", message_id); /* if message does not exist locally and in cache, it is new, so retrieve it */ if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) receive_message(lbs, list[index], message_id, error_str, TRUE); all_identical = FALSE; if (error_str[0]) { if (bcron) logf(lbs, "Error receiving message: %s", error_str); else rsprintf("Error receiving message: %s\n", error_str); } else if (!bcron) { if (getcfg_topgroup()) rsprintf("ID%d:\t", lbs->name_enc, message_id, message_id); else rsprintf("ID%d:\t", lbs->name_enc, message_id, message_id); rsprintf("%s\n", loc("Remote entry received")); } } else { if (!equal_md5(md5_cache[i_cache].md5_digest, md5_remote[i_remote].md5_digest)) { /* if message has changed remotely, receive it */ if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) receive_message(lbs, list[index], message_id, error_str, TRUE); all_identical = FALSE; if (error_str[0]) { if (bcron) logf(lbs, "Error receiving message: %s", error_str); else rsprintf("Error receiving message: %s\n", error_str); } else if (!bcron) { if (getcfg_topgroup()) rsprintf("ID%d:\t", lbs->name_enc, message_id, message_id); else rsprintf("ID%d:\t", lbs->name_enc, message_id, message_id); rsprintf("%s\n", loc("Remote entry received")); } } else { /* if message does not exist locally but in cache, delete remote message */ if (_logging_level > 1) logf(lbs, "MIRROR delete remote entry #%d", message_id); sprintf(str, "%d?cmd=%s&confirm=%s", message_id, loc("Delete"), loc("Yes")); combine_url(lbs, list[index], str, url, sizeof(url)); all_identical = FALSE; if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) { retrieve_url(url, &buffer); if (strstr(buffer, "Location: ")) { if (!bcron) rsprintf("ID%d:\t%s\n", message_id, loc("Entry deleted remotely")); } else { if (bcron) logf(lbs, "%s", loc("Error deleting remote entry")); else { if (isparam("debug")) rsputs(buffer); rsprintf("%s\n", loc("Error deleting remote entry")); } } free(buffer); } else rsprintf("ID%d:\t%s\n", message_id, loc("Entry deleted remotely")); md5_cache[i_cache].message_id = -1; } } } flush_return_buffer(); } free(md5_remote); /* save remote MD5s in file */ if (!all_identical) { n_remote = retrieve_remote_md5(lbs, list[index], &md5_remote, error_str); if (n_remote < 0) rsprintf("%s\n", error_str); /* keep conflicting messages in cache */ for (i = 0; i < n_cache; i++) if (md5_cache[i].message_id != -1) { if (i == 0) memcpy(md5_remote[0].md5_digest, md5_cache[0].md5_digest, 16); else for (j = 0; j < n_remote; j++) if (md5_remote[j].message_id == md5_cache[i].message_id) { memcpy(md5_remote[j].md5_digest, md5_cache[i].md5_digest, 16); break; } } if (!getcfg(lbs->name, "Mirror simulate", str) || atoi(str) == 0) save_md5(lbs, list[index], md5_remote, n_remote); if (md5_remote) free(md5_remote); } if (md5_cache) free(md5_cache); if (!bcron && all_identical) rsprintf(loc("All entries identical")); if (!bcron) rsprintf("\n"); } flush_return_buffer(); keep_alive = 0; } /*------------------------------------------------------------------*/ void synchronize(LOGBOOK * lbs, BOOL bcron) { int i; char str[256], pwd[256]; if (!bcron) { show_html_header(NULL, FALSE, loc("Synchronization"), TRUE); rsprintf("\n"); } if (lbs == NULL) { for (i = 0; lb_list[i].name[0]; i++) if (getcfg(lb_list[i].name, "mirror server", str)) { if (exist_top_group() && getcfg_topgroup()) if (lb_list[i].top_group[0] && !strieq(lb_list[i].top_group, getcfg_topgroup())) continue; /* if called by cron, set user name and password */ if (bcron && getcfg(lb_list[i].name, "mirror user", str)) { if (get_user_line(lb_list[i].name, str, pwd, NULL, NULL, NULL) == EL_SUCCESS) { setparam("unm", str); setparam("upwd", pwd); } } synchronize_logbook(&lb_list[i], bcron); } } else synchronize_logbook(lbs, bcron); if (!bcron) { rsprintf("\n", loc("Back")); rsprintf("
%s

\n"); rsprintf("\n"); flush_return_buffer(); keep_alive = 0; } } /*------------------------------------------------------------------*/ void display_line(LOGBOOK * lbs, int message_id, int number, char *mode, int expand, int level, BOOL printable, int n_line, int show_attachments, char *date, char *in_reply_to, char *reply_to, int n_attr_disp, char disp_attr[MAX_N_ATTR + 4][NAME_LENGTH], char attrib[MAX_N_ATTR][NAME_LENGTH], int n_attr, char *text, BOOL show_text, char attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], char *encoding, BOOL select, int *n_display, char *locked_by) { char str[NAME_LENGTH], ref[256], *nowrap, sclass[80], format[256], file_name[MAX_PATH_LENGTH], *slist, *svalue; char display[NAME_LENGTH], attr_icon[80]; int i, j, i_line, index, colspan; BOOL skip_comma; FILE *f; struct tm *pts; time_t ltime; slist = malloc((MAX_N_ATTR + 10) * NAME_LENGTH); svalue = malloc((MAX_N_ATTR + 10) * NAME_LENGTH); sprintf(ref, "../%s/%d", lbs->name_enc, message_id); if (strieq(mode, "Summary")) { if (number % 2 == 1) strcpy(sclass, "list1"); else strcpy(sclass, "list2"); } else if (strieq(mode, "Full")) strcpy(sclass, "list1"); else if (strieq(mode, "Threaded")) { if (level == 0) strcpy(sclass, "thread"); else strcpy(sclass, "threadreply"); } rsprintf(""); /* only single cell for threaded display */ if (strieq(mode, "Threaded")) { rsprintf("", sclass); if (locked_by && locked_by[0]) { sprintf(str, "%s %s", loc("Entry is currently edited by"), locked_by); rsprintf("\"%s\" ", str); } /* show select box */ if (select && level == 0) rsprintf("\n", (*n_display)++, message_id); for (i = 0; i < level; i++) rsprintf("   "); /* display "+" if expandable */ if (expand == 0 && reply_to[0]) rsprintf("+ "); } nowrap = printable ? "" : "nowrap"; skip_comma = FALSE; if (strieq(mode, "Threaded") && getcfg(lbs->name, "Thread display", display)) { /* check if to use icon from attributes */ attr_icon[0] = 0; if (getcfg(lbs->name, "Thread icon", attr_icon)) { for (i = 0; i < n_attr; i++) if (strieq(attr_list[i], attr_icon)) break; if (i < n_attr && attrib[i][0]) strcpy(attr_icon, attrib[i]); else attr_icon[0] = 0; } if (attr_icon[0]) rsprintf(" ", ref, attr_icon); else { /* if top level only, display reply icon if message has a reply */ if (getcfg(lbs->name, "Top level only", str) && atoi(str) == 1 && reply_to[0]) rsprintf(" ", ref); else { /* display standard icons */ if (level == 0) rsprintf(" ", ref); else rsprintf(" ", ref); } } j = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list((char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "message id", str, &j); add_subst_time(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "entry time", date, &j); strsubst(display, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, j); rsprintf("", ref); if (is_html(display)) rsputs(display); else rsputs2(display); rsprintf("\n"); } else { /* show select box */ if (select && !strieq(mode, "Threaded")) { rsprintf("", sclass); if (in_reply_to[0] == 0) rsprintf("\n", (*n_display)++, message_id); else rsprintf(" \n"); rsprintf("\n"); } if (strieq(mode, "Threaded")) rsprintf("", ref); for (index = 0; index < n_attr_disp; index++) { if (strieq(disp_attr[index], loc("ID"))) { if (strieq(mode, "Threaded")) { if (level == 0) rsprintf(" "); else rsprintf(" "); skip_comma = TRUE; } else { rsprintf("", sclass); if (locked_by && locked_by[0]) { sprintf(str, "%s %s", loc("Entry is currently edited by"), locked_by); rsprintf("\"%s\" ", str); } if (getcfg(lbs->name, "ID display", display)) { j = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list((char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "message id", str, &j); add_subst_time(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "entry time", date, &j); strsubst(display, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, j); } else sprintf(display, "%d", message_id); rsprintf("  %s  \n", ref, display); } } if (strieq(disp_attr[index], loc("Logbook"))) { if (strieq(mode, "Threaded")) { if (skip_comma) { rsprintf(" %s", lbs->name); skip_comma = FALSE; } else rsprintf(", %s", lbs->name); } else rsprintf("%s\n", sclass, nowrap, ref, lbs->name); } if (strieq(disp_attr[index], loc("Edit"))) { if (!strieq(mode, "Threaded")) { rsprintf("", sclass, nowrap, ref, loc("Edit")); rsprintf("\"%s\"\n", loc("Edit entry")); } } if (strieq(disp_attr[index], loc("Delete"))) { if (!strieq(mode, "Threaded")) { rsprintf("", sclass, nowrap, ref, loc("Delete")); rsprintf("\"%s\"\n", loc("Delete entry")); } } if (strieq(disp_attr[index], loc("Date"))) { if (!getcfg(lbs->name, "Time format", format)) strcpy(format, DEFAULT_TIME_FORMAT); ltime = date_to_ltime(date); pts = localtime(<ime); strftime(str, sizeof(str), format, pts); if (strieq(mode, "Threaded")) { if (skip_comma) { rsprintf(" %s", str); skip_comma = FALSE; } else rsprintf(", %s", str); } else rsprintf("%s\n", sclass, nowrap, ref, str); } for (i = 0; i < n_attr; i++) if (strieq(disp_attr[index], attr_list[i])) { if (strieq(mode, "Threaded")) { if (strieq(attr_options[i][0], "boolean")) { if (atoi(attrib[i]) == 1) { if (skip_comma) { rsprintf(" "); skip_comma = FALSE; } else rsprintf(", "); if (is_html(attrib[i])) rsputs(attrib[i]); else rsputs2(attrib[i]); rsprintf(" "); } } else if (attr_flags[i] & AF_ICON) { if (attrib[i][0]) rsprintf("  ", attrib[i]); } else { if (skip_comma) { rsprintf(" "); skip_comma = FALSE; } else rsprintf(", "); if (is_html(attrib[i])) rsputs(attrib[i]); else rsputs2(attrib[i]); } } else { if (strieq(attr_options[i][0], "boolean")) { if (atoi(attrib[i]) == 1) rsprintf ("\n", sclass); else rsprintf("\n", sclass); } else if (attr_flags[i] & AF_DATE) { if (!getcfg(lbs->name, "Date format", format)) strcpy(format, DEFAULT_DATE_FORMAT); ltime = atoi(attrib[i]); pts = localtime(<ime); if (ltime == 0) strcpy(str, "-"); else strftime(str, sizeof(str), format, pts); rsprintf("%s\n", sclass, ref, str); } else if (attr_flags[i] & AF_ICON) { rsprintf("", sclass); if (attrib[i][0]) rsprintf("", attrib[i]); rsprintf(" "); } else { rsprintf("", sclass); if (is_html(attrib[i])) rsputs(attrib[i]); else { rsprintf("", ref); sprintf(str, "Display %s", attr_list[i]); if (getcfg(lbs->name, str, display)) { j = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list((char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "message id", str, &j); add_subst_time(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "entry time", date, &j); strsubst(display, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, j); } else strcpy(display, attrib[i]); if (is_html(display)) rsputs(display); else rsputs2(display); rsprintf(""); } rsprintf(" "); } } } } if (strieq(mode, "Threaded")) rsprintf("\n"); } if (strieq(mode, "Threaded") && expand > 1 && show_text) { rsprintf("\n"); rsprintf(""); if (expand == 2) { for (i = i_line = 0; i < (int) sizeof(str) - 1; i++) { str[i] = text[i]; if (str[i] == '\n') i_line++; if (i_line == n_line) break; } str[i] = 0; /* only show text, not to rip apart HTML documents, e.g. only the start of a table */ strip_html(str); if (str[0]) strencode(str); else rsputs(" "); } else { if (strieq(encoding, "plain")) { rsputs("

");
            if (text[0])
               rsputs2(text);
            else
               rsputs(" ");
            rsputs("
"); } else if (text[0]) rsputs(text); else rsputs(" "); } rsprintf("\n"); } if (strieq(mode, "Summary") && n_line > 0 && show_text) { rsprintf(""); for (i = i_line = 0; i < (int) sizeof(str) - 1; i++) { str[i] = text[i]; if (str[i] == '\n') i_line++; if (i_line == n_line) break; } str[i] = 0; /* only show text, not to rip apart HTML documents, e.g. only the start of a table */ strip_html(str); if (str[0]) strencode(str); else rsputs(" "); rsputs("\n"); if (strieq(mode, "Threaded")) rsprintf("\n"); } colspan = n_attr_disp; if (select) colspan++; if (strieq(mode, "Full") && show_text) { if (!getcfg(lbs->name, "Show text", str) || atoi(str) == 1) { rsprintf("", colspan); if (strieq(encoding, "plain")) { rsputs("
");
            rsputs2(text);
            rsputs("
"); } else rsputs(text); rsprintf("\n"); } if (!show_attachments && attachment[0][0]) { rsprintf("", colspan); if (attachment[1][0]) rsprintf("%s: ", loc("Attachments")); else rsprintf("%s: ", loc("Attachment")); } for (index = 0; index < MAX_ATTACHMENTS; index++) { if (attachment[index][0]) { strcpy(str, attachment[index]); str[13] = 0; sprintf(ref, "../%s/%s/%s", lbs->name, str, attachment[index] + 14); url_encode(ref, sizeof(ref)); /* for file names with special characters like "+" */ for (i = 0; i < (int) strlen(attachment[index]); i++) str[i] = toupper(attachment[index][i]); str[i] = 0; if (!show_attachments) { rsprintf("%s     ", ref, attachment[index] + 14); } else { if (strstr(str, ".GIF") || strstr(str, ".JPG") || strstr(str, ".JPEG") || strstr(str, ".PNG")) { rsprintf ("%s %d: %s\n", colspan, loc("Attachment"), index + 1, ref, attachment[index] + 14); if (show_attachments) rsprintf ("", colspan, ref); } else { rsprintf ("%s %d: %s\n", colspan, loc("Attachment"), index + 1, ref, attachment[index] + 14); if ((strstr(str, ".TXT") || strstr(str, ".ASC") || strchr(str, '.') == NULL) && show_attachments) { /* display attachment */ rsprintf("
",
                              colspan);

                     strlcpy(file_name, lbs->data_dir, sizeof(file_name));

                     strlcat(file_name, attachment[index], sizeof(file_name));

                     f = fopen(file_name, "rt");
                     if (f != NULL) {
                        while (!feof(f)) {
                           str[0] = 0;
                           fgets(str, sizeof(str), f);
                           rsputs2(str);
                        }
                        fclose(f);
                     }

                     rsprintf("
\n"); } rsprintf("\n"); } } } } if (!show_attachments && attachment[0][0]) rsprintf("\n"); } free(slist); free(svalue); } /*------------------------------------------------------------------*/ void display_reply(LOGBOOK * lbs, int message_id, int printable, int expand, int n_line, int n_attr_disp, char disp_attr[MAX_N_ATTR + 4][NAME_LENGTH], BOOL show_text, int level) { char *date, *text, *in_reply_to, *reply_to, *encoding, *locked_by, *attachment, *attrib, *p; int status, size; text = malloc(TEXT_SIZE); attachment = malloc(MAX_ATTACHMENTS * MAX_PATH_LENGTH); attrib = malloc(MAX_N_ATTR * NAME_LENGTH); date = malloc(80); in_reply_to = malloc(80); reply_to = malloc(256); encoding = malloc(80); locked_by = malloc(256); if (locked_by == NULL) return; reply_to[0] = 0; size = TEXT_SIZE; status = el_retrieve(lbs, message_id, date, attr_list, (void *) attrib, lbs->n_attr, text, &size, in_reply_to, reply_to, (void *) attachment, encoding, locked_by); if (status != EL_SUCCESS) { free(text); free(attachment); free(attrib); free(date); free(in_reply_to); free(reply_to); free(encoding); free(locked_by); return; } display_line(lbs, message_id, 0, "threaded", expand, level, printable, n_line, FALSE, date, in_reply_to, reply_to, n_attr_disp, disp_attr, (void *) attrib, lbs->n_attr, text, show_text, NULL, encoding, 0, NULL, locked_by); if (reply_to[0]) { p = reply_to; do { display_reply(lbs, atoi(p), printable, expand, n_line, n_attr_disp, disp_attr, show_text, level + 1); while (*p && isdigit(*p)) p++; while (*p && (*p == ',' || *p == ' ')) p++; } while (*p); } free(text); free(attachment); free(attrib); free(date); free(in_reply_to); free(reply_to); free(encoding); free(locked_by); } /*------------------------------------------------------------------*/ int msg_compare(const void *m1, const void *m2) { return strcoll(((MSG_LIST *) m1)->string, ((MSG_LIST *) m2)->string); } int msg_compare_reverse(const void *m1, const void *m2) { return strcoll(((MSG_LIST *) m2)->string, ((MSG_LIST *) m1)->string); } /*------------------------------------------------------------------*/ char *param_in_str(char *str, char *param) { char *p; p = str; do { if (stristr(p, param) == NULL) return NULL; p = stristr(p, param); /* if parameter is value of another parameter, skip it */ if (p > str + 1 && *(p - 1) == '=') p += strlen(param); else return p; if (*p == 0) return NULL; } while (1); } /*------------------------------------------------------------------*/ void subst_param(char *str, int size, char *param, char *value) { int len; char *p1, *p2, *s; if (!value[0]) { /* remove parameter */ s = param_in_str(str, param); if (s == NULL) return; /* remove parameter */ p1 = s - 1; for (p2 = p1 + strlen(param) + 1; *p2 && *p2 != '&'; p2++); strlcpy(p1, p2, size - ((int) p1 - (int) str)); if (!strchr(str, '?') && strchr(str, '&')) *strchr(str, '&') = '?'; return; } if ((p1 = param_in_str(str, param)) == NULL) { if (strchr(str, '?')) strlcat(str, "&", size); else strlcat(str, "?", size); strlcat(str, param, size); strlcat(str, "=", size); strlcat(str, value, size); return; } p1 += strlen(param) + 1; for (p2 = p1; *p2 && *p2 != '&'; p2++); len = (int) p2 - (int) p1; if (len > (int) strlen(value)) { /* new value is shorter than old one */ strlcpy(p1, value, size - ((int) p1 - (int) str)); strlcpy(p1 + strlen(value), p2, size - ((int) p1 + strlen(value) - (int) str)); } else { /* new value is longer than old one */ s = malloc(size); strlcpy(s, p2, size); strlcpy(p1, value, size - ((int) p1 - (int) str)); strlcat(p1, s, size - ((int) p1 + strlen(value) - (int) str)); free(s); } } /*------------------------------------------------------------------*/ BOOL is_user_allowed(LOGBOOK * lbs, char *command) { char str[1000], users[2000]; char list[MAX_N_LIST][NAME_LENGTH]; int i, n; /* check for user level access */ if (!getcfg(lbs->name, "Password file", str)) return TRUE; /* check for deny */ sprintf(str, "Deny %s", command); if (getcfg(lbs->name, str, users)) { /* check if current user in list */ n = strbreak(users, list, MAX_N_LIST, ","); for (i = 0; i < n; i++) if (strieq(list[i], getparam("unm"))) break; if (i < n) return FALSE; } /* check admin command */ if (strieq(command, loc("Admin"))) { if (getcfg(lbs->name, "Admin user", str)) { if (strstr(str, getparam("unm")) != 0) return TRUE; else return FALSE; } } /* check for allow */ sprintf(str, "Allow %s", command); if (!getcfg(lbs->name, str, users)) return TRUE; /* check if current user in list */ n = strbreak(users, list, MAX_N_LIST, ","); for (i = 0; i < n; i++) if (strieq(list[i], getparam("unm"))) return TRUE; return FALSE; } /*------------------------------------------------------------------*/ BOOL is_command_allowed(LOGBOOK * lbs, char *command) { char str[1000], menu_str[1000], other_str[1000]; char menu_item[MAX_N_LIST][NAME_LENGTH], admin_user[80]; int i, n; if (command[0] == 0) return TRUE; /* check for guest access */ if (!getcfg(lbs->name, "Guest Menu commands", menu_str) || *getparam("unm") != 0) getcfg(lbs->name, "Menu commands", menu_str); /* default menu commands */ if (menu_str[0] == 0) { strcpy(menu_str, "Back, New, Edit, Delete, Reply, Find, "); if (getcfg(lbs->name, "Password file", str)) { if (!getcfg(lbs->name, "Admin user", str) || strstr(str, getparam("unm")) != 0) { strcat(menu_str, "Admin, "); strcat(menu_str, "Change elogd.cfg, "); if (getcfg(lbs->name, "Mirror server", str)) strcat(menu_str, "Synchronize, "); if (!getcfg("global", "Admin user", str) || strstr(str, getparam("unm")) != 0) { if (lbs->top_group[0]) { sprintf(str, "Change [global %s]", lbs->top_group); strcat(menu_str, str); strcat(menu_str, ", "); } if (!lbs->top_group[0] || (!getcfg_simple("global", "Admin user", str) || strstr(str, getparam("unm")) != 0)) { strcat(menu_str, "Change [global]"); strcat(menu_str, ", "); } } } strcat(menu_str, "Config, Logout, "); } else { if (getcfg(lbs->name, "Mirror server", str)) strcat(menu_str, "Synchronize, "); strcat(menu_str, "Config, "); strcat(menu_str, "Change [global]"); strcat(menu_str, ", "); } strcat(menu_str, "Help, "); } else { /* check for admin command */ n = strbreak(menu_str, menu_item, MAX_N_LIST, ","); menu_str[0] = 0; admin_user[0] = 0; getcfg(lbs->name, "Admin user", admin_user); for (i = 0; i < n; i++) { if (strcmp(menu_item[i], "Admin") == 0) { if (strstr(admin_user, getparam("unm")) == NULL) continue; } strcat(menu_str, menu_item[i]); strcat(menu_str, ", "); } if (strstr(admin_user, getparam("unm")) != NULL) { strcat(menu_str, "Change elogd.cfg, "); if (!getcfg("global", "Admin user", str) || strstr(str, getparam("unm")) != 0) { if (lbs->top_group[0]) { sprintf(str, "Change [global %s]", lbs->top_group); strcat(menu_str, str); strcat(menu_str, ", "); } if (!lbs->top_group[0] || (!getcfg_simple("global", "Admin user", str) || strstr(str, getparam("unm")) != 0)) { strcat(menu_str, "Change [global]"); strcat(menu_str, ", "); } } } } /* check find menu commands */ str[0] = 0; if (!getcfg(lbs->name, "Guest Find Menu commands", str) || *getparam("unm") != 0) getcfg(lbs->name, "Find Menu commands", str); if (str[0]) strlcat(menu_str, str, sizeof(menu_str)); else { strlcat(menu_str, "New, Find, Select, Last x, Help, ", sizeof(menu_str)); if (getcfg(lbs->name, "Password file", str)) strlcat(menu_str, "Admin, Config, Logout, ", sizeof(menu_str)); else strlcat(menu_str, "Config, ", sizeof(menu_str)); } strcpy(other_str, "Update, Upload, Submit, Back, Search, Save, Download, CSV Import, "); strcat(other_str, "Cancel, First, Last, Previous, Next, Requested, Forgot, "); /* admin commands */ if (getcfg(lbs->name, "Admin user", str) && *getparam("unm") && strstr(str, getparam("unm")) != 0) { strcat(other_str, "Remove user, New user, Activate, "); } else if (getcfg(lbs->name, "Self register", str) && atoi(str) > 0) { strcat(other_str, "Remove user, New user, "); } /* allow import if CSV import is present */ if (strstr(menu_str, loc("CSV Import"))) strcat(other_str, "Import, "); /* allow change password if "config" possible */ if (strieq(command, loc("Change password")) && strstr(menu_str, "Config")) { return TRUE; } /* exclude non-localized submit for elog */ else if (command[0] && strieq(command, "Submit")) { return TRUE; } /* exclude other non-localized commands */ else if (command[0] && strieq(command, "GetMD5")) { return TRUE; } /* check if command is present in the menu list */ else if (command[0]) { n = strbreak(menu_str, menu_item, MAX_N_LIST, ","); for (i = 0; i < n; i++) if (strieq(command, menu_item[i]) || strieq(command, loc(menu_item[i]))) break; if (i == n) { n = strbreak(other_str, menu_item, MAX_N_LIST, ","); for (i = 0; i < n; i++) if (strieq(command, loc(menu_item[i]))) break; if (i == n) return FALSE; } } return TRUE; } /*------------------------------------------------------------------*/ void build_ref(char *ref, int size, char *mode, char *expand) { if (strchr(getparam("cmdline"), '?')) strlcat(ref, strchr(getparam("cmdline"), '?'), size); /* eliminate old search */ if (strstr(ref, "cmd=Search&")) strcpy(strstr(ref, "cmd=Search&"), strstr(ref, "cmd=Search&") + 11); /* eliminate old mode if new one is present */ if (mode[0]) subst_param(ref, size, "mode", mode); /* eliminate old expand if new one is present */ if (expand[0]) subst_param(ref, size, "expand", expand); /* eliminate old last= */ subst_param(ref, size, "last", getparam("last")); } /*------------------------------------------------------------------*/ void show_page_filters(LOGBOOK * lbs, int n_msg, int page_n, BOOL mode_commands, BOOL threaded) { int cur_exp, n, i, j, index; char ref[256], str[NAME_LENGTH], comment[NAME_LENGTH], list[MAX_N_LIST][NAME_LENGTH], option[NAME_LENGTH]; rsprintf("\n"); rsprintf("\n"); rsprintf("\n"); if (mode_commands) { rsprintf("\n"); } if (getcfg(lbs->name, "Quick filter", str)) { rsprintf("\n"); } rsprintf("
\n"); if (!getcfg(lbs->name, "Show text", str) || atoi(str) == 1) { if (page_n != 1) sprintf(ref, "page%d", page_n); else ref[0] = 0; build_ref(ref, sizeof(ref), "full", ""); rsprintf(" %s |", ref, loc("Full")); } if (page_n != 1) sprintf(ref, "page%d", page_n); else ref[0] = 0; build_ref(ref, sizeof(ref), "summary", ""); rsprintf(" %s |", ref, loc("Summary")); if (page_n != 1) sprintf(ref, "page%d", page_n); else ref[0] = 0; build_ref(ref, sizeof(ref), "threaded", ""); rsprintf(" %s ", ref, loc("Threaded")); if (threaded) { if (page_n != 1) sprintf(ref, "page%d", page_n); else ref[0] = 0; cur_exp = 1; if (getcfg(lbs->name, "Expand default", str)) cur_exp = atoi(str); if (isparam("expand")) cur_exp = atoi(getparam("expand")); if (cur_exp > 0) { sprintf(str, "%d", cur_exp > 0 ? cur_exp - 1 : 0); build_ref(ref, sizeof(ref), "", str); rsprintf("| %s ", ref, loc("Collapse")); } else rsprintf("| %s ", loc("Collapse")); if (cur_exp < 3) { if (page_n != 1) sprintf(ref, "page%d", page_n); else ref[0] = 0; sprintf(str, "%d", cur_exp < 3 ? cur_exp + 1 : 3); build_ref(ref, sizeof(ref), "", str); rsprintf("| %s ", ref, loc("Expand")); } else rsprintf("| %s ", loc("Expand")); } rsprintf("\n"); n = strbreak(str, list, MAX_N_LIST, ","); for (index = 0; index < n; index++) { if (strieq(list[index], loc("Date"))) { i = atoi(getparam("last")); rsprintf(" \n", loc("Show last")); rsprintf("\n"); } else { rsprintf(" \n", list[index]); for (i = 0; i < MAX_N_ATTR; i++) if (strieq(attr_list[i], list[index])) break; if (attr_options[i][0][0] == 0) { if (attr_flags[i] & AF_DATE) { rsprintf("\n"); } else { rsprintf("\n", list[index], getparam(list[index])); } } else { rsprintf(" \n"); } } } rsprintf(" %d %s", n_msg, loc("Entries")); rsprintf("
\n\n"); } /*------------------------------------------------------------------*/ void show_page_navigation(int n_msg, int page_n, int n_page) { int i, num_pages, skip; char ref[256]; if (!page_n || n_msg <= n_page) return; rsprintf("\n"); rsprintf("%s \n", loc("Goto page")); if (page_n > 1) { sprintf(ref, "page%d", page_n - 1); build_ref(ref, sizeof(ref), "", ""); rsprintf("%s  ", ref, loc("Previous")); } if (page_n && n_msg > n_page) { /* number of pages */ num_pages = (n_msg - 1) / n_page + 1; skip = FALSE; for (i = 1; i <= num_pages; i++) { sprintf(ref, "page%d", i); build_ref(ref, sizeof(ref), "", ""); if (i <= 3 || (i >= page_n - 1 && i <= page_n + 1) || i >= num_pages - 2) { if (i > 1 && !skip) rsprintf(", \n"); skip = FALSE; } else { if (!skip) rsprintf(" ... "); skip = TRUE; } if (skip) continue; if (page_n == i) rsprintf("%d", i); else rsprintf("%d", ref, i); /* if (i == num_pages ) rsprintf("  \n"); else rsprintf(", "); */ } rsprintf("  \n"); } if (page_n != -1 && n_page < n_msg && page_n * n_page < n_msg) { sprintf(ref, "page%d", page_n + 1); build_ref(ref, sizeof(ref), "", ""); rsprintf("%s  ", ref, loc("Next")); } if (page_n != -1 && n_page < n_msg) { sprintf(ref, "page"); build_ref(ref, sizeof(ref), "", ""); rsprintf("%s\n", ref, loc("All")); } rsprintf("\n"); } /*------------------------------------------------------------------*/ void show_select_navigation(LOGBOOK * lbs) { int i, n_log; char str[NAME_LENGTH]; char lbk_list[MAX_N_LIST][NAME_LENGTH]; rsprintf("\n"); rsprintf("\n"); rsprintf("%s: \n", loc("Selected entries")); rsprintf("\n", loc("Toggle all")); if (!getcfg(lbs->name, "Menu commands", str) || strstr(str, "Delete")) { rsprintf("\n", loc("Delete")); } if (getcfg(lbs->name, "Menu commands", str) && strstr(str, "Copy to")) { rsprintf("\n", loc("Copy to")); rsprintf("\n"); } if (getcfg(lbs->name, "Menu commands", str) && strstr(str, "Move to")) { rsprintf("\n", loc("Move to")); rsprintf("\n"); } rsprintf("\n\n"); } /*------------------------------------------------------------------*/ time_t retrieve_date(char *index, BOOL bstart) { int year, month, day, current_year, current_month, current_day; char pm[10], py[10], pd[10], str[NAME_LENGTH]; struct tm tms; time_t ltime; sprintf(pm, "m%s", index); sprintf(py, "y%s", index); sprintf(pd, "d%s", index); time(<ime); memcpy(&tms, localtime(<ime), sizeof(tms)); current_year = tms.tm_year + 1900; current_month = tms.tm_mon + 1; current_day = tms.tm_mday; if (!*getparam(pm) && !*getparam(py) && !*getparam(pd)) return 0; /* if year not given, use current year */ if (!*getparam(py)) year = current_year; else year = atoi(getparam(py)); if (year < 1970) { sprintf(str, "Error: Year %s out of range", getparam(py)); show_error(str); return -1; } /* if month not given, use current month */ if (*getparam(pm)) { month = atoi(getparam(pm)); } else month = current_month; if (*getparam(pd)) day = atoi(getparam(pd)); else { /* if day not given, use 1 if start date */ if (bstart) day = 1; else { /* use last day of month */ memset(&tms, 0, sizeof(struct tm)); tms.tm_year = year - 1900; tms.tm_mon = month - 1 + 1; tms.tm_mday = 1; tms.tm_hour = 12; if (tms.tm_year < 90) tms.tm_year += 100; ltime = mktime(&tms); ltime -= 3600 * 24; memcpy(&tms, localtime(<ime), sizeof(struct tm)); day = tms.tm_mday; } } memset(&tms, 0, sizeof(struct tm)); tms.tm_year = year - 1900; tms.tm_mon = month - 1; tms.tm_mday = day; tms.tm_hour = 0; if (tms.tm_year < 90) tms.tm_year += 100; ltime = mktime(&tms); if (!bstart) /* end time is first second of next day */ ltime += 3600 * 24; return ltime; } /*------------------------------------------------------------------*/ void show_elog_list(LOGBOOK * lbs, INT past_n, INT last_n, INT page_n, char *info) { int i, j, n, index, size, status, d1, m1, y1, d2, m2, y2, n_line; int current_year, current_month, current_day, printable, n_logbook, n_display, reverse, n_attr_disp, total_n_msg, n_msg, search_all, message_id, n_page, i_start, i_stop, in_reply_to_id; char date[80], attrib[MAX_N_ATTR][NAME_LENGTH], disp_attr[MAX_N_ATTR + 4][NAME_LENGTH], *list, *text, *text1, *text2, in_reply_to[80], reply_to[MAX_REPLY_TO * 10], attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], encoding[80], locked_by[256], str[NAME_LENGTH], ref[256], img[80], comment[NAME_LENGTH], mode[80], mid[80], menu_str[1000], menu_item[MAX_N_LIST][NAME_LENGTH], param[NAME_LENGTH], format[80]; char *p, *pt, *pt1, *pt2, *slist, *svalue, *gattr; BOOL show_attachments, threaded, csv, xml, mode_commands, expand, filtering, disp_filter, show_text; time_t ltime, ltime_start, ltime_end, now, ltime1, ltime2; struct tm tms, *ptms; MSG_LIST *msg_list; LOGBOOK *lbs_cur; /* redirect if enpty parameters */ if (strstr(_cmdline, "=&")) { while ((pt1 = strstr(_cmdline, "=&")) != NULL) { pt2 = pt1; while (*pt1 != '&' && *pt1 != '?') pt1--; pt1++; strcpy(param, pt1); param[(int) pt2 - (int) pt1] = 0; strcpy(pt1, pt2 + 2); /* remove param from lastcmd if present */ if ((pt1 = strstr(_cmdline, "lastcmd=")) != NULL) { sprintf(str, "%s%%3D", param); if ((pt1 = strstr(_cmdline, str)) != NULL) { pt2 = pt1 + strlen(str); while (*pt2 && *pt2 != '%') pt2++; if (*pt2 == '%') pt2 += 3; strcpy(pt1, pt2); } } } if (_cmdline[strlen(_cmdline) - 1] == '=') { pt1 = _cmdline + strlen(_cmdline) - 1; while (*pt1 != '&' && *pt1 != '?') pt1--; pt1++; strcpy(param, pt1); if (param[strlen(param) - 1] == '=') param[strlen(param) - 1] = 0; *pt1 = 0; /* remove param from lastcmd if present */ if ((pt1 = strstr(_cmdline, "lastcmd=")) != NULL) { sprintf(str, "%s%%3D", param); if ((pt1 = strstr(_cmdline, str)) != NULL) { pt2 = pt1 + strlen(str); while (*pt2 && *pt2 != '%' && *pt2 != '&') pt2++; if (*pt2 == '%') pt2 += 3; strcpy(pt1, pt2); } } } /* add reverse=0 if not present */ if (strstr(_cmdline, "reverse=") == NULL && getcfg(lbs->name, "Reverse sort", str) && atoi(str) == 1) { if (strchr(_cmdline, '?')) strlcat(_cmdline, "&reverse=0", sizeof(_cmdline)); else strlcat(_cmdline, "?reverse=0", sizeof(_cmdline)); } if (_cmdline[strlen(_cmdline)-1] == '&') _cmdline[strlen(_cmdline)-1] = 0; redirect(lbs, _cmdline); return; } /* redirect "go" command */ if (isparam("lastcmd")) { strlcpy(str, getparam("lastcmd"), sizeof(str)); url_decode(str); /* subsitute "last" in command line from new parameter */ if (isparam("last")) { if (strieq(getparam("last"), "_all_")) subst_param(str, sizeof(str), "last", ""); else subst_param(str, sizeof(str), "last", getparam("last")); } /* subsitute attributes in command line from new parameter */ for (i = 0; i < MAX_N_ATTR; i++) if (isparam(attr_list[i])) { if (strieq(getparam(attr_list[i]), "_all_")) subst_param(str, sizeof(str), attr_list[i], ""); else subst_param(str, sizeof(str), attr_list[i], getparam(attr_list[i])); } redirect(lbs, str); return; } /* remove remaining "_all_" in parameters */ if (strieq(getparam("last"), "_all_")) { strlcpy(str, _cmdline, sizeof(str)); subst_param(str, sizeof(str), "last", ""); redirect(lbs, str); return; } if (strstr(_cmdline, "_all_")) { strlcpy(str, _cmdline, sizeof(str)); while (strstr(str, "_all_")) { p = strstr(str, "_all_"); pt = p + 5; while (p > str && *p != '&') p--; strcpy(p, pt); } if (strchr(str, '&') && !strchr(str, '?')) *strchr(str, '&') = '?'; redirect(lbs, str); } slist = malloc((MAX_N_ATTR + 10) * NAME_LENGTH); svalue = malloc((MAX_N_ATTR + 10) * NAME_LENGTH); gattr = malloc(MAX_N_ATTR * NAME_LENGTH); list = malloc(10000); printable = atoi(getparam("Printable")); /* in printable mode, display all pages */ if (printable) page_n = -1; if (*getparam("Reverse")) reverse = atoi(getparam("Reverse")); else { reverse = 0; if (getcfg(lbs->name, "Reverse sort", str)) reverse = atoi(str); } /* default mode */ strcpy(mode, "Summary"); show_attachments = FALSE; /* for page display, get mode from config file */ if (past_n || last_n || page_n) { if (getcfg(lbs->name, "Display Mode", str)) strcpy(mode, str); if (*getparam("mode")) strcpy(mode, getparam("mode")); } else { /* for find result, get mode from find form */ strcpy(mode, getparam("mode")); if (mode[0] == 0) strcpy(mode, "Full"); } threaded = strieq(mode, "threaded"); csv = strieq(mode, "CSV1") || strieq(mode, "CSV2"); xml = strieq(mode, "XML"); if (csv || xml) { page_n = -1; /* display all pages */ show_attachments = FALSE; /* hide attachments */ } /* supersede mode if in parameter */ if (*getparam("attach")) show_attachments = (*getparam("attach") > 0); /*---- convert dates to ltime ----*/ time(&now); ptms = localtime(&now); current_year = ptms->tm_year + 1900; current_month = ptms->tm_mon + 1; current_day = ptms->tm_mday; ltime_end = ltime_start = 0; d1 = m1 = y1 = d2 = m2 = y2 = 0; if (!past_n && !last_n) { ltime_start = retrieve_date("a", TRUE); if (ltime_start < 0) { free(slist); free(svalue); free(gattr); free(list); return; } if (ltime_start) { memcpy(&tms, localtime(<ime_start), sizeof(struct tm)); y1 = tms.tm_year + 1900; m1 = tms.tm_mon + 1; d1 = tms.tm_mday; } ltime_end = retrieve_date("b", FALSE); if (ltime_end < 0) { free(slist); free(svalue); free(gattr); free(list); return; } if (ltime_end) { if (ltime_end <= ltime_start) { sprintf(str, "Error: Start date after end date"); show_error(str); free(slist); free(svalue); free(gattr); free(list); return; } memcpy(&tms, localtime(<ime_end), sizeof(struct tm)); y2 = tms.tm_year + 1900; m2 = tms.tm_mon + 1; d2 = tms.tm_mday; } } if (ltime_start && ltime_end && ltime_start > ltime_end) { show_error(loc("Error: start date after end date")); free(slist); free(svalue); free(gattr); free(list); return; } /*---- assemble message list ----*/ /* check for search all */ search_all = atoi(getparam("all")); if (getcfg(lbs->name, "Search all logbooks", str) && atoi(str) == 0) search_all = 0; n_msg = 0; n_display = 0; if (search_all) { /* count logbooks */ for (n_logbook = 0;; n_logbook++) { if (!lb_list[n_logbook].name[0]) break; if (lbs->top_group[0] && !strieq(lbs->top_group, lb_list[n_logbook].top_group)) continue; if (isparam("unm") && !check_login_user(&lb_list[n_logbook], getparam("unm"))) continue; n_msg += *lb_list[n_logbook].n_el_index; } } else { n_logbook = 1; n_msg = *lbs->n_el_index; } msg_list = malloc(sizeof(MSG_LIST) * n_msg); lbs_cur = lbs; for (i = n = 0; i < n_logbook; i++) { if (search_all) lbs_cur = &lb_list[i]; if (lbs->top_group[0] && !strieq(lbs->top_group, lbs_cur->top_group)) continue; if (isparam("unm") && !check_login_user(lbs_cur, getparam("unm"))) continue; for (j = 0; j < *lbs_cur->n_el_index; j++) { msg_list[n].lbs = lbs_cur; msg_list[n].index = j; sprintf(msg_list[n].string, "%010d", (int) lbs_cur->el_index[j].file_time); msg_list[n].in_reply_to = lbs_cur->el_index[j].in_reply_to; n++; } } /*---- apply start/end date cut ----*/ if (past_n) ltime_start = now - 3600 * 24 * past_n; if (last_n && last_n < n_msg) { for (i = n_msg - last_n - 1; i >= 0; i--) msg_list[i].lbs = NULL; } if (ltime_start) { for (i = 0; i < n_msg; i++) if (msg_list[i].lbs && msg_list[i].lbs->el_index[msg_list[i].index].file_time < ltime_start) msg_list[i].lbs = NULL; } if (ltime_end) { for (i = 0; i < n_msg; i++) if (msg_list[i].lbs && msg_list[i].lbs->el_index[msg_list[i].index].file_time > ltime_end) msg_list[i].lbs = NULL; } if (isparam("last")) { n = atoi(getparam("last")); if (n > 0) { for (i = 0; i < n_msg; i++) if (msg_list[i].lbs && msg_list[i].lbs->el_index[msg_list[i].index].file_time < now - 3600 * 24 * n) msg_list[i].lbs = NULL; } } /*---- filter message list ----*/ filtering = FALSE; show_text = TRUE; for (i = 0; i < lbs->n_attr; i++) { /* check if attribute filter */ if (*getparam(attr_list[i])) break; if (attr_flags[i] & AF_DATE) { sprintf(str, "%da", i); if (retrieve_date(str, TRUE)) break; sprintf(str, "%db", i); if (retrieve_date(str, TRUE)) break; } /* check if sort by attribute */ if (strieq(getparam("sort"), attr_list[i]) || strieq(getparam("rsort"), attr_list[i])) break; } /* turn on filtering if found */ if (i < lbs->n_attr) filtering = TRUE; if (*getparam("subtext")) filtering = TRUE; text = malloc(TEXT_SIZE); text1 = malloc(TEXT_SIZE); text2 = malloc(TEXT_SIZE); if (text2 == NULL) { show_error("Out of memory"); free(slist); free(svalue); free(gattr); free(list); return; } /* do filtering */ for (index = 0; index < n_msg; index++) { if (!msg_list[index].lbs) continue; /* retrieve message */ size = TEXT_SIZE; message_id = msg_list[index].lbs->el_index[msg_list[index].index].message_id; in_reply_to_id = msg_list[index].lbs->el_index[msg_list[index].index].in_reply_to; if (filtering) { status = el_retrieve(msg_list[index].lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to, reply_to, attachment, encoding, locked_by); if (status != EL_SUCCESS) break; } for (i = 0; i < lbs->n_attr; i++) { if (*getparam(attr_list[i])) { if (attr_flags[i] & AF_DATE) { ltime = atoi(getparam(attr_list[i])); /* today 12h noon */ time(&now); memcpy(&tms, localtime(&now), sizeof(struct tm)); tms.tm_hour = 12; tms.tm_min = 0; tms.tm_sec = 0; now = mktime(&tms); /* negative i: last [i] days */ if (ltime < 0) if (atoi(attrib[i]) < now + ltime * 3600 * 24 || atoi(attrib[i]) > now) break; /* positive i: next [i] days */ if (ltime > 0) if (atoi(attrib[i]) > now + ltime * 3600 * 24 || atoi(attrib[i]) < now) break; } else { strcpy(str, getparam(attr_list[i])); /* if value starts with '$', substitute it */ if (str[0] == '$') { j = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, attrib, TRUE); sprintf(mid, "%d", message_id); add_subst_list((char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "message id", mid, &j); add_subst_time(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "entry time", date, &j); strsubst(str, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, j); setparam(attr_list[i], str); } for (j = 0; j < (int) strlen(str); j++) str[j] = toupper(str[j]); str[j] = 0; for (j = 0; j < (int) strlen(attrib[i]); j++) text1[j] = toupper(attrib[i][j]); text1[j] = 0; if (strstr(text1, str) == NULL) break; } } } if (i < lbs->n_attr) { msg_list[index].lbs = NULL; continue; } /* apply filter for AF_DATE attributes */ if (filtering) for (i = 0; i < lbs->n_attr; i++) if (attr_flags[i] & AF_DATE) { sprintf(str, "%da", i); ltime = retrieve_date(str, TRUE); if (ltime > 0 && atoi(attrib[i]) < ltime) { msg_list[index].lbs = NULL; continue; } sprintf(str, "%db", i); ltime = retrieve_date(str, FALSE); if (ltime > 0 && (atoi(attrib[i]) > ltime || atoi(attrib[i]) == 0)) { msg_list[index].lbs = NULL; continue; } } if (*getparam("subtext")) { strcpy(str, getparam("subtext")); for (i = 0; i < (int) strlen(str); i++) str[i] = toupper(str[i]); str[i] = 0; for (i = 0; i < (int) strlen(text); i++) text1[i] = toupper(text[i]); text1[i] = 0; if (atoi(getparam("sall")) && strstr(text1, str) == NULL) { /* search text in attributes */ for (i = 0; i < lbs->n_attr; i++) { for (j = 0; j < (int) strlen(attrib[i]); j++) text1[j] = toupper(attrib[i][j]); text1[j] = 0; if (strstr(text1, str) != NULL) break; } if (i == lbs->n_attr) { msg_list[index].lbs = NULL; continue; } } else if (strstr(text1, str) == NULL) { msg_list[index].lbs = NULL; continue; } } /* in threaded mode, find message head */ if (threaded && in_reply_to_id) { do { message_id = in_reply_to_id; /* search index of message */ for (i = 0; i < *msg_list[index].lbs->n_el_index; i++) if (msg_list[index].lbs->el_index[i].message_id == message_id) break; /* stop if not found */ if (i == *msg_list[index].lbs->n_el_index) break; in_reply_to_id = msg_list[index].lbs->el_index[i].in_reply_to; } while (in_reply_to_id); /* if head not found, skip message */ if (i == *msg_list[index].lbs->n_el_index) { msg_list[index].lbs = NULL; continue; } /* check if message head already in list */ for (j = 0; j < index; j++) if (msg_list[j].lbs == msg_list[index].lbs && msg_list[j].index == i) break; if (j < index) { /* set date from current message, if later */ if (strcmp(msg_list[j].string, msg_list[index].string) < 0) strcpy(msg_list[j].string, msg_list[index].string); msg_list[index].lbs = NULL; // delete current message continue; } else { msg_list[index].index = i; // replace current message with message head } } /* add attribute for sorting */ for (i = 0; i < lbs->n_attr; i++) { if (strieq(getparam("sort"), attr_list[i]) || strieq(getparam("rsort"), attr_list[i])) { strlcpy(msg_list[index].string, attrib[i], 256); } if (strieq(getparam("sort"), loc("ID")) || strieq(getparam("rsort"), loc("ID"))) { sprintf(msg_list[index].string, "%08d", message_id); } if (strieq(getparam("sort"), loc("Logbook")) || strieq(getparam("rsort"), loc("Logbook"))) { strlcpy(msg_list[index].string, msg_list[index].lbs->name, 256); } } if (isparam("rsort")) reverse = 1; if (isparam("sort")) reverse = 0; } /*---- remove duplicate messages ----*/ for (i = 0; i < n_msg; i++) for (j = i + 1; j < n_msg; j++) if (msg_list[i].lbs == msg_list[j].lbs && msg_list[i].index == msg_list[j].index) { msg_list[i].lbs = NULL; break; } /*---- compact messasges ----*/ total_n_msg = n_msg; for (i = j = 0; i < n_msg; i++) if (msg_list[i].lbs) memcpy(&msg_list[j++], &msg_list[i], sizeof(MSG_LIST)); n_msg = j; /*---- sort messasges ----*/ qsort(msg_list, n_msg, sizeof(MSG_LIST), reverse ? msg_compare_reverse : msg_compare); /*---- number of messages per page ----*/ n_attr_disp = n_line = 0; n_page = 1000000; i_start = 0; i_stop = n_msg - 1; if (page_n) { if (getcfg(lbs->name, "Entries per page", str)) n_page = atoi(str); else n_page = 20; if (isparam("npp")) n_page = atoi(getparam("npp")); if (page_n != -1) { i_start = (page_n - 1) * n_page; i_stop = i_start + n_page - 1; if (i_start >= n_msg && n_msg > 0) { page_n = 1; i_start = 0; } if (i_stop >= n_msg) i_stop = n_msg - 1; } } /*---- header ----*/ if (getcfg(lbs->name, "Summary Page Title", str)) { i = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, NULL, TRUE); strsubst(str, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, i); strip_html(str); } else sprintf(str, "ELOG %s", lbs->name); if (csv) { /* no menus and tables */ show_plain_header(0, "export.csv"); for (i = 0; i < lbs->n_attr; i++) { strlcpy(str, attr_list[i], sizeof(str)); if (str[0]) { rsputs("\""); pt1 = str; while ((pt2 = strchr(pt1, '"')) != NULL) { *pt2 = 0; rsputs(pt1); rsputs("\"\""); pt1 = pt2 + 1; } rsputs(pt1); rsputs("\""); } if (i < lbs->n_attr - 1) { if (strieq(mode, "CSV1")) rsprintf(","); else rsprintf(";"); } else rsprintf("\r\n"); } } else if (xml) { /* no menus and tables */ show_plain_header(0, "export.xml"); rsputs("\n"); rsprintf("\n", VERSION); rsprintf("\n"); } else { show_standard_header(lbs, TRUE, str, NULL); /*---- title ----*/ strcpy(str, ", "); if (past_n == 1) strcat(str, loc("Last day")); else if (past_n > 1) sprintf(str + strlen(str), loc("Last %d days"), past_n); else if (last_n) sprintf(str + strlen(str), loc("Last %d entries"), last_n); else if (page_n == -1) sprintf(str + strlen(str), loc("all entries")); else if (page_n) sprintf(str + strlen(str), loc("Page %d of %d"), page_n, (n_msg - 1) / n_page + 1); if (strlen(str) == 2) str[0] = 0; if (printable) show_standard_title(lbs->name, str, 1); else show_standard_title(lbs->name, str, 0); /*---- menu buttons ----*/ if (!printable) { rsprintf("\n"); /* current command line for select command */ strcpy(str, getparam("cmdline")); /* remove select switch */ if (strstr(str, "select=1")) { *strstr(str, "select=1") = 0; if (strlen(str) > 1 && (str[strlen(str) - 1] == '&' || str[strlen(str) - 1] == '?')) str[strlen(str) - 1] = 0; } /* store current command line as hidden parameter for page navigation */ if (str[0] && !strieq(str, "?")) { rsprintf("\n", str); } if (!getcfg(lbs->name, "Guest Find menu commands", menu_str) || *getparam("unm") != 0) getcfg(lbs->name, "Find menu commands", menu_str); /* default menu commands */ if (menu_str[0] == 0) { strcpy(menu_str, "New, Find, Select, CSV Import, "); if (getcfg(lbs->name, "Password file", str)) strcat(menu_str, "Config, Logout, "); else strcat(menu_str, "Config, "); if (getcfg(lbs->name, "Mirror server", str)) strcat(menu_str, "Synchronize, "); strcat(menu_str, "Last x, Help"); } n = strbreak(menu_str, menu_item, MAX_N_LIST, ","); for (i = 0; i < n; i++) { if (is_user_allowed(lbs, menu_item[i])) { if (strieq(menu_item[i], "Last x")) { if (past_n) { sprintf(str, loc("Last %d days"), past_n * 2); rsprintf(" %s |\n", past_n * 2, mode, str); } if (last_n) { sprintf(str, loc("Last %d entries"), last_n * 2); rsprintf(" %s |\n", last_n * 2, mode, str); } } else if (strieq(menu_item[i], "Select")) { strcpy(str, getparam("cmdline")); if (atoi(getparam("select")) == 1) { /* remove select switch */ if (strstr(str, "select=1")) { *strstr(str, "select=1") = 0; if (strlen(str) > 1 && (str[strlen(str) - 1] == '&' || str[strlen(str) - 1] == '?')) str[strlen(str) - 1] = 0; } } else { /* add select switch */ if (strchr(str, '?')) strcat(str, "&select=1"); else strcat(str, "?select=1"); } rsprintf(" %s |\n", str, loc("Select")); } else { strcpy(str, loc(menu_item[i])); url_encode(str, sizeof(str)); if (i < n - 1) rsprintf(" %s |\n", str, loc(menu_item[i])); else rsprintf(" %s \n", str, loc(menu_item[i])); } } } rsprintf("\n\n"); } /*---- find menu text ----*/ if (getcfg(lbs->name, "find menu text", str) && !printable) { FILE *f; char file_name[256], *buf; rsprintf("\n"); /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } f = fopen(file_name, "rb"); if (f != NULL) { fseek(f, 0, SEEK_END); size = TELL(fileno(f)); fseek(f, 0, SEEK_SET); buf = malloc(size + 1); fread(buf, 1, size, f); buf[size] = 0; fclose(f); rsputs(buf); } else rsprintf("
Error: file \"%s\" not found
", file_name); rsprintf("
"); } /*---- display filters ----*/ disp_filter = *getparam("ma") || *getparam("ya") || *getparam("da") || *getparam("mb") || *getparam("yb") || *getparam("db") || *getparam("subtext"); for (i = 0; i < lbs->n_attr; i++) if (*getparam(attr_list[i]) && (attr_flags[i] & AF_DATE) == 0) disp_filter = TRUE; for (i = 0; i < lbs->n_attr; i++) if (attr_flags[i] & AF_DATE) { sprintf(str, "%da", i); ltime = retrieve_date(str, TRUE); if (ltime > 0) disp_filter = TRUE; sprintf(str, "%db", i); ltime = retrieve_date(str, FALSE); if (ltime > 0) disp_filter = TRUE; } if (disp_filter) { rsprintf("\n"); rsprintf("\n"); if (*getparam("ma") || *getparam("ya") || *getparam("da")) { memset(&tms, 0, sizeof(struct tm)); tms.tm_year = y1 - 1900; tms.tm_mon = m1 - 1; tms.tm_mday = d1; tms.tm_hour = 12; if (tms.tm_year < 90) tms.tm_year += 100; mktime(&tms); strcpy(format, "%x"); strftime(str, sizeof(str), format, &tms); rsprintf("", loc("Start date")); rsprintf("", str); } if (*getparam("mb") || *getparam("yb") || *getparam("db")) { /* calculate previous day */ memset(&tms, 0, sizeof(struct tm)); tms.tm_year = y2 - 1900; tms.tm_mon = m2 - 1; tms.tm_mday = d2; tms.tm_hour = 12; if (tms.tm_year < 90) tms.tm_year += 100; ltime = mktime(&tms); ltime -= 3600 * 24; memcpy(&tms, localtime(<ime), sizeof(struct tm)); strcpy(format, "%x"); strftime(str, sizeof(str), format, &tms); rsprintf("", loc("End date")); rsprintf("", str); } for (i = 0; i < lbs->n_attr; i++) { if (attr_flags[i] & AF_DATE) { sprintf(str, "%da", i); ltime1 = retrieve_date(str, TRUE); sprintf(str, "%db", i); ltime2 = retrieve_date(str, TRUE); if (ltime1 > 0 || ltime2 > 0) { rsprintf("", attr_list[i]); rsprintf("", comment); } } else if (*getparam(attr_list[i])) { comment[0] = 0; if (attr_flags[i] & AF_ICON) { sprintf(str, "Icon comment %s", getparam(attr_list[i])); getcfg(lbs->name, str, comment); } if (comment[0] == 0) strcpy(comment, getparam(attr_list[i])); rsprintf("", attr_list[i]); rsprintf("", comment); } } if (*getparam("subtext")) { rsprintf("", loc("Text")); rsprintf ("", getparam("subtext")); } rsprintf("
%s:%s
%s:%s
%s:"); if (ltime1) { memcpy(&tms, localtime(<ime1), sizeof(struct tm)); strcpy(format, "%x"); strftime(str, sizeof(str), format, &tms); if (ltime2 > 0) rsprintf("%s %s", loc("From"), str); else rsprintf("%s %s", loc("After"), str); } if (ltime2) { memcpy(&tms, localtime(<ime2), sizeof(struct tm)); strcpy(format, "%x"); strftime(str, sizeof(str), format, &tms); if (ltime1 > 0) rsprintf(" %s %s", loc("to"), str); else rsprintf("%s %s", loc("Before"), str); } rsprintf("
%s:%s
%s:%s
\n\n"); } /* get number of summary lines */ n_line = 3; if (getcfg(lbs->name, "Summary lines", str)) n_line = atoi(str); /* get mode commands flag */ mode_commands = TRUE; if (getcfg(lbs->name, "Mode commands", str) && atoi(str) == 0) mode_commands = FALSE; /*---- notification message ----*/ if (info && info[0]) { rsprintf("%s\n", info); } /*---- page navigation ----*/ if (!printable) { show_page_filters(lbs, n_msg, page_n, mode_commands, threaded); show_page_navigation(n_msg, page_n, n_page); } /*---- select navigation ----*/ if (atoi(getparam("select")) == 1) show_select_navigation(lbs); /*---- table titles ----*/ /* overall listing table */ rsprintf("\n"); size = printable ? 2 : 3; show_text = TRUE; list[0] = 0; getcfg(lbs->name, "List display", list); /* evaluate Guest display list */ if (getcfg(lbs->name, "Password file", str) && getcfg(lbs->name, "Guest list display", str) && !isparam("unm")) { strcpy(list, str); n = strbreak(list, (char (*)[NAME_LENGTH]) gattr, MAX_N_ATTR, ","); for (j = 0; j < n; j++) if (strieq(gattr + j * NAME_LENGTH, "text")) break; if (j == n) show_text = FALSE; } if (list[0]) { n_attr_disp = strbreak(list, disp_attr, MAX_N_ATTR, ","); if (search_all) { for (i = n_attr_disp - 1; i >= 0; i--) strcpy(disp_attr[i + 1], disp_attr[i]); strcpy(disp_attr[0], loc("Logbook")); n_attr_disp++; } } else { if (search_all) { n_attr_disp = lbs->n_attr + 3; strcpy(disp_attr[0], loc("Logbook")); strcpy(disp_attr[1], loc("ID")); strcpy(disp_attr[2], loc("Date")); memcpy(disp_attr + 3, attr_list, sizeof(attr_list)); } else { n_attr_disp = lbs->n_attr + 2; strcpy(disp_attr[0], loc("ID")); strcpy(disp_attr[1], loc("Date")); memcpy(disp_attr + 2, attr_list, sizeof(attr_list)); } } if (threaded) { } else { rsprintf("\n"); /* empty title for selection box */ if (atoi(getparam("select")) == 1) rsprintf("\n"); for (i = 0; i < n_attr_disp; i++) { /* assemble current command line, replace sort statements */ strcpy(ref, getparam("cmdline")); if (strstr(ref, "&sort=")) { p = strstr(ref, "&sort=") + 1; while (*p && *p != '&') p++; strcpy(strstr(ref, "&sort="), p); } if (strstr(ref, "&rsort=")) { p = strstr(ref, "&rsort=") + 1; while (*p && *p != '&') p++; strcpy(strstr(ref, "&rsort="), p); } if (strstr(ref, "?sort=")) *strstr(ref, "?sort=") = 0; if (strstr(ref, "?rsort=")) *strstr(ref, "?rsort=") = 0; strcpy(str, disp_attr[i]); url_encode(str, sizeof(str)); if (strcmp(getparam("sort"), disp_attr[i]) == 0) { if (strchr(ref, '?')) sprintf(ref + strlen(ref), "&rsort=%s", str); else sprintf(ref + strlen(ref), "?rsort=%s", str); } else { if (strchr(ref, '?')) sprintf(ref + strlen(ref), "&sort=%s", str); else sprintf(ref + strlen(ref), "?sort=%s", str); } img[0] = 0; if (strcmp(getparam("sort"), disp_attr[i]) == 0) strcpy(img, ""); else if (strcmp(getparam("rsort"), disp_attr[i]) == 0) strcpy(img, ""); if (strieq(disp_attr[i], "Edit") || strieq(disp_attr[i], "Delete")) rsprintf("\n", disp_attr[i]); else rsprintf("\n", ref, disp_attr[i], img); } if (!strieq(mode, "Full") && n_line > 0 && show_text) rsprintf("\n", loc("Text")); rsprintf("\n\n"); } } /* if (!csv && !xml) */ /*---- display message list ----*/ for (index = i_start; index <= i_stop; index++) { size = TEXT_SIZE; message_id = msg_list[index].lbs->el_index[msg_list[index].index].message_id; status = el_retrieve(msg_list[index].lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to, reply_to, attachment, encoding, locked_by); if (status != EL_SUCCESS) break; if (csv) { for (i = 0; i < lbs->n_attr; i++) { strlcpy(str, attrib[i], sizeof(str)); if (str[0]) { rsputs("\""); pt1 = str; while ((pt2 = strchr(pt1, '"')) != NULL) { *pt2 = 0; rsputs(pt1); rsputs("\"\""); pt1 = pt2 + 1; } rsputs(pt1); rsputs("\""); } if (i < lbs->n_attr - 1) { if (strieq(mode, "CSV1")) rsprintf(","); else rsprintf(";"); } else rsprintf("\r\n"); } } else if (xml) { rsputs("\t\n"); rsprintf("\t\t%d\n", message_id); rsprintf("\t\t%s\n", date); for (i = 0; i < lbs->n_attr; i++) { strcpy(str, attr_list[i]); for (j = 0; j < (int) strlen(str); j++) if (!isalnum(str[j])) str[j] = '_'; rsprintf("\t\t<%s>", str); xmlencode(attrib[i]); rsprintf("\n", str); } rsputs("\t\t"); xmlencode(text); rsputs("\n"); rsputs("\t\n"); } else { /*---- add highlighting for searched subtext ----*/ if (*getparam("subtext")) { strcpy(str, getparam("subtext")); for (i = 0; i < (int) strlen(str); i++) str[i] = toupper(str[i]); for (i = 0; i < (int) strlen(text); i++) text1[i] = toupper(text[i]); text1[i] = 0; text2[0] = 0; pt = text; /* original text */ pt1 = text1; /* upper-case text */ pt2 = text2; /* text with inserted coloring */ do { p = strstr(pt1, str); size = (int) (p - pt1); if (p != NULL) { pt1 = p + strlen(str); /* copy first part original text */ memcpy(pt2, pt, size); pt2 += size; pt += size; /* add coloring 1st part */ /* here: \001='<', \002='>', /003='"', and \004=' ' */ /* see also rsputs2(char* ) */ if (strieq(encoding, "plain") || !strieq(mode, "Full")) strcpy(pt2, "\001B\004style=\003color:black;background-color:#ffff66\003\002"); else strcpy(pt2, ""); pt2 += strlen(pt2); /* copy origial search text */ memcpy(pt2, pt, strlen(str)); pt2 += strlen(str); pt += strlen(str); /* add coloring 2nd part */ if (strieq(encoding, "plain") || !strieq(mode, "Full")) strcpy(pt2, "\001/B\002"); else strcpy(pt2, ""); pt2 += strlen(pt2); } } while (p != NULL); strcpy(pt2, pt); strcpy(text, text2); } /*---- display line ----*/ expand = 1; if (threaded) { if (getcfg(lbs->name, "Expand default", str)) expand = atoi(str); if (isparam("expand")) expand = atoi(getparam("expand")); } display_line(msg_list[index].lbs, message_id, index, mode, expand, 0, printable, n_line, show_attachments, date, in_reply_to, reply_to, n_attr_disp, disp_attr, attrib, lbs->n_attr, text, show_text, attachment, encoding, atoi(getparam("select")), &n_display, locked_by); if (threaded) { if (reply_to[0] && expand > 0) { p = reply_to; do { display_reply(msg_list[index].lbs, atoi(p), printable, expand, n_line, n_attr_disp, disp_attr, show_text, 1); while (*p && isdigit(*p)) p++; while (*p && (*p == ',' || *p == ' ')) p++; } while (*p); } } } /* if (!csv && !xml) */ } /* for() */ if (!csv && !xml) { rsprintf("
 %s%s%s%s
\n"); if (n_display) rsprintf("\n", n_display); rsprintf("\n"); if (n_msg == 0) rsprintf("%s", loc("No entries found")); /*---- page navigation ----*/ if (!printable) show_page_navigation(n_msg, page_n, n_page); rsprintf("\n"); show_bottom_text(lbs); rsprintf("\r\n"); } if (xml) { rsputs("
\n"); } free(slist); free(svalue); free(gattr); free(list); free(msg_list); free(text); free(text1); free(text2); } /*------------------------------------------------------------------*/ int compose_email(LOGBOOK * lbs, char *mail_to, int message_id, char attrib[MAX_N_ATTR][NAME_LENGTH], char *mail_param, int old_mail, char att_file[MAX_ATTACHMENTS][256]) { int i, j, k, n, flags, status; char str[NAME_LENGTH + 100], str2[256], mail_from[256], *mail_text, smtp_host[256], subject[256], format[256]; char slist[MAX_N_ATTR + 10][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH]; char list[MAX_PARAM][NAME_LENGTH], url[256], comment[256]; time_t ltime; struct tm *pts; if (!getcfg("global", "SMTP host", smtp_host)) { show_error(loc("No SMTP host defined in [global] section of configuration file")); return 0; } flags = 63; if (getcfg(lbs->name, "Email format", str)) flags = atoi(str); if (getcfg(lbs->name, "Use Email from", mail_from)) { j = build_subst_list(lbs, slist, svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list(slist, svalue, "message id", str, &j); strsubst(mail_from, slist, svalue, j); if (strncmp(mail_from, "mailto:", 7) == 0) strcpy(mail_from, mail_from + 7); } else sprintf(mail_from, "ELog@%s", host_name); mail_text = malloc(TEXT_SIZE + 1000); mail_text[0] = 0; if (flags & 1) { if (getcfg(lbs->name, "Use Email heading", str)) { if (old_mail) { if (!getcfg(lbs->name, "Use Email heading edit", str)) getcfg(lbs->name, "Use Email heading", str); } sprintf(mail_text + strlen(mail_text), str); } else { if (old_mail) sprintf(mail_text + strlen(mail_text), loc("A old entry has been updated on %s"), host_name); else sprintf(mail_text + strlen(mail_text), loc("A new entry has been submitted on %s"), host_name); } sprintf(mail_text + strlen(mail_text), "\r\n\r\n"); } if (flags & 32) sprintf(mail_text + strlen(mail_text), "%s : %s\r\n", loc("Logbook"), lbs->name); if (flags & 2) { for (j = 0; j < lbs->n_attr; j++) { strcpy(str, " "); memcpy(str, attr_list[j], strlen(attr_list[j])); comment[0] = 0; if (attr_flags[j] & AF_ICON) { sprintf(str2, "Icon comment %s", attrib[j]); getcfg(lbs->name, str2, comment); } else if (attr_flags[j] & AF_DATE) { if (!getcfg(lbs->name, "Date format", format)) strcpy(format, DEFAULT_DATE_FORMAT); ltime = atoi(attrib[j]); pts = localtime(<ime); if (ltime == 0) strcpy(comment, "-"); else strftime(comment, sizeof(str), format, pts); } if (!comment[0]) strcpy(comment, attrib[j]); if (strieq(attr_options[j][0], "boolean")) strcpy(comment, atoi(attrib[j]) ? loc("Yes") : loc("No")); for (k = strlen(str) - 1; k > 0; k--) if (str[k] != ' ') break; if (k < 20) sprintf(str + 20, ": %s\r\n", comment); else sprintf(str + k + 1, ": %s\r\n", comment); strcpy(mail_text + strlen(mail_text), str); } } /* compose subject from attributes */ if (getcfg(lbs->name, "Use Email Subject", subject)) { j = build_subst_list(lbs, slist, svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list(slist, svalue, "message id", str, &j); strsubst(subject, slist, svalue, j); } else { if (old_mail) strcpy(subject, "Updated ELOG entry"); else strcpy(subject, "New ELOG entry"); } /* try to get URL from referer */ if (!getcfg("global", "URL", str)) { if (referer[0]) strcpy(str, referer); else { if (tcp_port == 80) sprintf(str, "http://%s/", host_name); else sprintf(str, "http://%s:%d/", host_name, tcp_port); strcat(str, lbs->name); strcat(str, "/"); } } else { strlcat(str, lbs->name_enc, sizeof(str)); strlcat(str, "/", sizeof(str)); } sprintf(url, "%s%d", str, message_id); if (flags & 4) { sprintf(mail_text + strlen(mail_text), "\r\n%s URL : %s\r\n", loc("Logbook"), url); } if (flags & 8) { if (*getparam("text")) sprintf(mail_text + strlen(mail_text), "\r\n=================================\r\n\r\n%s", getparam("text")); } status = 0; if (flags & 16) { if (getcfg(lbs->name, "Omit Email to", str) && atoi(str) == 1) status = sendmail(lbs, smtp_host, mail_from, mail_to, subject, mail_text, FALSE, url, att_file); else status = sendmail(lbs, smtp_host, mail_from, mail_to, subject, mail_text, TRUE, url, att_file); } else { if (getcfg(lbs->name, "Omit Email to", str) && atoi(str) == 1) status = sendmail(lbs, smtp_host, mail_from, mail_to, subject, mail_text, FALSE, url, NULL); else status = sendmail(lbs, smtp_host, mail_from, mail_to, subject, mail_text, TRUE, url, NULL); } if (status < 0) { sprintf(str, loc("Error sending Email via \"%s\""), smtp_host); url_encode(str, sizeof(str)); sprintf(mail_param, "?error=%s", str); } else { if (!getcfg(lbs->name, "Display email recipients", str) || atoi(str) == 1) { if (mail_param[0] == 0) strcpy(mail_param, "?"); else strcat(mail_param, "&"); n = strbreak(mail_to, list, MAX_PARAM, ","); if (n < 10) { for (i = 0; i < n && i < MAX_PARAM; i++) { sprintf(mail_param + strlen(mail_param), "mail%d=%s", i, list[i]); if (i < n - 1) strcat(mail_param, "&"); } } else { sprintf(str, "%d%%20%s", n, loc("recipients")); sprintf(mail_param + strlen(mail_param), "mail0=%s", str); } } } free(mail_text); return status; } /*------------------------------------------------------------------*/ int execute_shell(LOGBOOK * lbs, int message_id, char attrib[MAX_N_ATTR][NAME_LENGTH], char *sh_cmd) { int i; char slist[MAX_N_ATTR + 10][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH]; char shell_cmd[1000], str[80]; if (!enable_execute) { printf("Shell execution not enabled via -x flag.\n"); return SUCCESS; } strlcpy(shell_cmd, sh_cmd, sizeof(shell_cmd)); i = build_subst_list(lbs, slist, svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list(slist, svalue, "message id", str, &i); strsubst(shell_cmd, slist, svalue, i); logf(lbs, "SHELL \"%s\"", shell_cmd); system(shell_cmd); return SUCCESS; } /*------------------------------------------------------------------*/ int add_attribute_option(LOGBOOK * lbs, char *attrname, char *attrvalue) { int fh, i, length; char str[NAME_LENGTH], *buf, *buf2, *p1, *p2, *p3; fh = open(config_file, O_RDWR | O_BINARY, 644); if (fh < 0) { sprintf(str, loc("Cannot open file %s"), config_file); strcat(str, ": "); strcat(str, strerror(errno)); show_error(str); return 0; } /* read previous contents */ length = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); buf = malloc(length + strlen(attrvalue) + 3); assert(buf); read(fh, buf, length); buf[length] = 0; /* find location of options */ sprintf(str, "Options %s", attrname); p1 = (char *) find_param(buf, lbs->name, str); if (p1 == NULL) { sprintf(str, "MOptions %s", attrname); p1 = (char *) find_param(buf, lbs->name, str); } if (p1 == NULL) { sprintf(str, "ROptions %s", attrname); p1 = (char *) find_param(buf, lbs->name, str); } if (p1 == NULL) return 0; p2 = strchr(p1, '\n'); if (p2 && *(p2 - 1) == '\r') p2--; /* save tail */ buf2 = NULL; if (p2) { buf2 = malloc(strlen(p2) + 1); assert(buf2); strlcpy(buf2, p2, strlen(p2) + 1); } /* add option */ p3 = strchr(p1, '\n'); if (p3 == NULL) p3 = p1 + strlen(p1); while (*(p3 - 1) == '\n' || *(p3 - 1) == '\r' || *(p3 - 1) == ' ' || *(p3 - 1) == '\t') p3--; sprintf(p3, ", %s", attrvalue); if (p2) { strlcat(buf, buf2, length + strlen(attrvalue) + 3); free(buf2); } lseek(fh, 0, SEEK_SET); i = write(fh, buf, strlen(buf)); if (i < (int) strlen(buf)) { sprintf(str, loc("Cannot write to %s"), config_file); strcat(str, ": "); strcat(str, strerror(errno)); show_error(str); close(fh); free(buf); return 0; } #ifdef _MSC_VER chsize(fh, TELL(fh)); #else ftruncate(fh, TELL(fh)); #endif close(fh); free(buf); /* force re-read of config file */ check_config(); return 1; } /*------------------------------------------------------------------*/ int set_attributes(LOGBOOK * lbs, char attributes[][NAME_LENGTH], int n) { int fh, i, length, size; char str[NAME_LENGTH], *buf, *buf2, *p1, *p2, *p3; fh = open(config_file, O_RDWR | O_BINARY, 644); if (fh < 0) { sprintf(str, loc("Cannot open file %s"), config_file); strcat(str, ": "); strcat(str, strerror(errno)); show_error(str); return 0; } /* determine length of attributes */ for (i = size = 0; i < n; i++) size += strlen(attributes[i]) + 2; /* read previous contents */ length = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); buf = malloc(length + size + 3); assert(buf); read(fh, buf, length); buf[length] = 0; /* find location of attributes */ p1 = (char *) find_param(buf, lbs->name, "Attributes"); if (p1 == NULL) { sprintf(str, loc("No 'Attributes' option present in %s"), config_file); show_error(str); return 0; } p2 = strchr(p1, '\n'); if (p2 && *(p2 - 1) == '\r') p2--; /* save tail */ buf2 = NULL; if (p2) { buf2 = malloc(strlen(p2) + 1); assert(buf2); strlcpy(buf2, p2, strlen(p2) + 1); } /* add list */ p3 = strchr(p1, '='); if (p3 == NULL) return 0; p3++; while (*p3 == ' ') p3++; for (i = 0; i < n - 1; i++) { sprintf(p3, "%s, ", attributes[i]); p3 += strlen(p3); } sprintf(p3, "%s", attributes[i]); if (p2) { strlcat(buf, buf2, length + size + 3); free(buf2); } lseek(fh, 0, SEEK_SET); i = write(fh, buf, strlen(buf)); if (i < (int) strlen(buf)) { sprintf(str, loc("Cannot write to %s"), config_file); strcat(str, ": "); strcat(str, strerror(errno)); show_error(str); close(fh); free(buf); return 0; } #ifdef _MSC_VER chsize(fh, TELL(fh)); #else ftruncate(fh, TELL(fh)); #endif close(fh); free(buf); /* force re-read of config file */ check_config(); return 1; } /*------------------------------------------------------------------*/ void submit_elog(LOGBOOK * lbs) { char str[1000], str2[1000], file_name[256], error[1000], date[80], mail_list[MAX_N_LIST][NAME_LENGTH], list[10000], attrib[MAX_N_ATTR][NAME_LENGTH], subst_str[MAX_PATH_LENGTH], in_reply_to[80], reply_to[MAX_REPLY_TO * 10], user[256], user_email[256], email_notify[256], mail_param[1000], *mail_to, att_file[MAX_ATTACHMENTS][256], slist[MAX_N_ATTR + 10][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH], ua[NAME_LENGTH]; int i, j, n, missing, first, index, mindex, suppress, message_id, resubmit_orig, mail_to_size, ltime, year, month, day; BOOL bedit; struct tm tms; /* check for required attributs */ missing = 0; for (i = 0; i < lbs->n_attr; i++) { strcpy(ua, attr_list[i]); btou(ua); if (attr_flags[i] & AF_REQUIRED) { if (attr_flags[i] & AF_DATE) { sprintf(str, "d%d", i); if (*getparam(str) == 0) missing = 1; sprintf(str, "m%d", i); if (*getparam(str) == 0) missing = 1; sprintf(str, "y%d", i); if (*getparam(str) == 0) missing = 1; if (missing) break; } else if ((attr_flags[i] & AF_MULTI)) { for (j = 0; j < MAX_N_LIST; j++) { sprintf(str, "%s_%d", ua, j); if (getparam(str) && *getparam(str)) break; } if (j == MAX_N_LIST) { missing = 1; break; } } else if (*getparam(ua) == 0) { missing = 1; break; } } } if (missing) { sprintf(error, ""); sprintf(error + strlen(error), loc("Error: Attribute %s not supplied"), attr_list[i]); sprintf(error + strlen(error), ".

\n"); sprintf(error + strlen(error), loc("Please go back and enter the %s field"), attr_list[i]); strcat(error, ".\n"); show_error(error); return; } /* check for numeric attributes */ for (index = 0; index < lbs->n_attr; index++) if (attr_flags[index] & AF_NUMERIC) { strcpy(ua, attr_list[index]); btou(ua); strlcpy(str, getparam(ua), sizeof(str)); for (j = 0; i < (int) strlen(str); i++) if (!isdigit(str[i])) break; if (i < (int) strlen(str)) { sprintf(error, loc("Error: Attribute %s must be numeric"), attr_list[index]); show_error(error); return; } } /* check for extended attributs */ for (i = 0; i < lbs->n_attr; i++) { strcpy(ua, attr_list[i]); btou(ua); if (isparam(ua) && attr_options[i][0][0]) { if (strieq(attr_options[i][0], "boolean")) { if (atoi(getparam(ua)) != 0 && atoi(getparam(ua)) != 1) { sprintf(error, loc("Error: Value %s not allowed for boolean attributes"), getparam(ua)); show_error(error); return; } } else { /* check if option exists */ for (j = 0; attr_options[i][j][0]; j++) if (strieq(attr_options[i][j], getparam(ua))) break; /* check if option without {n} exists */ if (!attr_options[i][j][0]) { for (j = 0; attr_options[i][j][0]; j++) { strcpy(str, attr_options[i][j]); if (strchr(str, '{')) *strchr(str, '{') = 0; if (strieq(str, getparam(ua))) break; } } if (!attr_options[i][j][0] && *getparam(ua)) { if (attr_flags[i] & AF_EXTENDABLE) { if (!add_attribute_option(lbs, attr_list[i], getparam(ua))) return; } else { sprintf(error, loc("Error: Attribute option %s not existing"), getparam(ua)); show_error(error); return; } } } } } /* get attachments */ for (i = 0; i < MAX_ATTACHMENTS; i++) { sprintf(str, "attachment%d", i); strcpy(att_file[i], getparam(str)); } /* retrieve attributes */ for (i = 0; i < lbs->n_attr; i++) { strcpy(ua, attr_list[i]); btou(ua); if (attr_flags[i] & AF_MULTI) { attrib[i][0] = 0; first = 1; for (j = 0; j < MAX_N_LIST; j++) { sprintf(str, "%s_%d", ua, j); if (getparam(str)) { if (*getparam(str)) { if (first) first = 0; else strlcat(attrib[i], " | ", NAME_LENGTH); if (strlen(attrib[i]) + strlen(getparam(str)) < NAME_LENGTH - 2) strlcat(attrib[i], getparam(str), NAME_LENGTH); else break; } } else break; } } else if (attr_flags[i] & AF_DATE) { sprintf(str, "y%d", i); year = atoi(getparam(str)); if (year < 100) year += 2000; sprintf(str, "m%d", i); month = atoi(getparam(str)); sprintf(str, "d%d", i); day = atoi(getparam(str)); if (month == 0 || day == 0) strcpy(attrib[i], ""); else { memset(&tms, 0, sizeof(struct tm)); tms.tm_year = year - 1900; tms.tm_mon = month - 1; tms.tm_mday = day; tms.tm_hour = 12; ltime = mktime(&tms); sprintf(attrib[i], "%d", ltime); } } else { strlcpy(attrib[i], getparam(ua), NAME_LENGTH); /* strip trailing "{...}" */ if (strchr(attrib[i], '{') && strchr(attrib[i], '}')) *strchr(attrib[i], '{') = 0; } } /* compile substitution list */ n = build_subst_list(lbs, slist, svalue, attrib, TRUE); if (atoi(getparam("edit_id"))) add_subst_list(slist, svalue, "message id", getparam("edit_id"), &n); /* substitute attributes */ for (i = 0; i < lbs->n_attr; i++) { if (!*getparam("edit_id")) { sprintf(str, "Subst %s", attr_list[i]); if (getcfg(lbs->name, str, subst_str)) { strsubst(subst_str, slist, svalue, n); strcpy(attrib[i], subst_str); } } } message_id = 0; reply_to[0] = 0; in_reply_to[0] = 0; date[0] = 0; resubmit_orig = 0; bedit = FALSE; if (*getparam("edit_id") && *getparam("resubmit") && atoi(getparam("resubmit")) == 1) { resubmit_orig = atoi(getparam("edit_id")); bedit = TRUE; /* get old links */ el_retrieve(lbs, resubmit_orig, NULL, NULL, NULL, 0, NULL, 0, in_reply_to, reply_to, NULL, NULL, NULL); /* if not message head, move all preceeding messages */ /* outcommented, users want only resubmitted message occur at end (see what's new) if (in_reply_to[0]) { do { resubmit_orig = atoi(in_reply_to); el_retrieve(lbs, resubmit_orig, NULL, NULL, NULL, 0, NULL, 0, in_reply_to, reply_to, NULL, NULL); } while (in_reply_to[0]); } */ message_id = atoi(getparam("edit_id")); strcpy(in_reply_to, ""); strcpy(reply_to, ""); date[0] = 0; } else { if (*getparam("edit_id")) { bedit = TRUE; message_id = atoi(getparam("edit_id")); strcpy(in_reply_to, ""); strcpy(reply_to, ""); strcpy(date, ""); } else strcpy(in_reply_to, getparam("reply_to")); } if (_logging_level > 1) { if (isparam("edit_id")) logf(lbs, "EDIT entry #%d", message_id); else logf(lbs, "NEW entry #%d", message_id); } message_id = el_submit(lbs, message_id, bedit, date, attr_list, attrib, lbs->n_attr, getparam("text"), in_reply_to, reply_to, *getparam("html") ? "HTML" : "plain", att_file, TRUE, NULL); if (message_id <= 0) { sprintf(str, loc("New entry cannot be written to directory \"%s\""), lbs->data_dir); strcat(str, "\n

"); strcat(str, loc("Please check that it exists and elogd has write access")); show_error(str); return; } /* resubmit thread if requested */ if (resubmit_orig) message_id = el_move_message_thread(lbs, resubmit_orig); /*---- email notifications ----*/ suppress = atoi(getparam("suppress")); /* check for mail submissions */ mail_param[0] = 0; mail_to = malloc(256); mail_to[0] = 0; mail_to_size = 256; if (suppress) { strcpy(mail_param, "?suppress=1"); } else { if (!(*getparam("edit_id") && getcfg(lbs->name, "Suppress Email on edit", str) && atoi(str) == 1)) { /* go throuch "Email xxx" in configuration file */ for (index = mindex = 0; index <= lbs->n_attr; index++) { strcpy(ua, attr_list[index]); btou(ua); if (index < lbs->n_attr) { strcpy(str, "Email "); if (strchr(attr_list[index], ' ')) sprintf(str + strlen(str), "\"%s\"", attr_list[index]); else strlcat(str, attr_list[index], sizeof(str)); strcat(str, " "); if (attr_flags[index] & AF_MULTI) { sprintf(str2, "%s_%d", ua, mindex); mindex++; if (mindex == MAX_N_LIST) mindex = 0; else index--; /* repeat this loop */ } else strcpy(str2, ua); if (strchr(getparam(str2), ' ')) sprintf(str + strlen(str), "\"%s\"", getparam(str2)); else strlcat(str, getparam(str2), sizeof(str)); } else sprintf(str, "Email ALL"); if (getcfg(lbs->name, str, list)) { n = strbreak(list, mail_list, MAX_N_LIST, ","); if (verbose) printf("\n%s to %s\n\n", str, list); for (i = 0; i < n; i++) { j = build_subst_list(lbs, slist, svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list(slist, svalue, "message id", str, &j); add_subst_time(lbs, slist, svalue, "entry time", date, &j); strsubst(mail_list[i], slist, svalue, j); if ((int) strlen(mail_to) + (int) strlen(mail_list[i]) >= mail_to_size) { mail_to_size += 256; mail_to = realloc(mail_to, mail_to_size); } strcat(mail_to, mail_list[i]); strcat(mail_to, ","); } } } if (!getcfg(lbs->name, "Suppress Email to users", str) || atoi(str) == 0) { /* go through password file */ for (index = 0;; index++) { if (!enum_user_line(lbs, index, user)) break; get_user_line(lbs->name, user, NULL, NULL, user_email, email_notify); if (email_notify[0]) { /* check if user has access to this logbook */ if (!check_login_user(lbs, user)) continue; if ((int) strlen(mail_to) + (int) strlen(user_email) >= mail_to_size) { mail_to_size += 256; mail_to = realloc(mail_to, mail_to_size); } strcat(mail_to, user_email); strcat(mail_to, ","); } } } } } if (strlen(mail_to) > 0) { mail_to[strlen(mail_to) - 1] = 0; /* strip last ',' */ if (compose_email (lbs, mail_to, message_id, attrib, mail_param, *getparam("edit_id"), att_file) == 0) return; } free(mail_to); /*---- shell execution ----*/ if (!atoi(getparam("shell_suppress"))) { if (!*getparam("edit_id")) { if (getcfg(lbs->name, "Execute new", str)) execute_shell(lbs, message_id, attrib, str); } else { if (getcfg(lbs->name, "Execute edit", str)) execute_shell(lbs, message_id, attrib, str); } } /*---- custom submit page ----*/ if (getcfg(lbs->name, "Submit page", str)) { /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } send_file_direct(file_name); return; } sprintf(str, "%d%s", message_id, mail_param); redirect(lbs, str); } /*------------------------------------------------------------------*/ void submit_elog_mirror(LOGBOOK * lbs) { char str[1000], date[80], attrib_value[MAX_N_ATTR][NAME_LENGTH], attrib_name[MAX_N_ATTR][NAME_LENGTH], in_reply_to[80], encoding[80], reply_to[MAX_REPLY_TO * 10], att_file[MAX_ATTACHMENTS][256], name[NAME_LENGTH], value[NAME_LENGTH]; int i, message_id, n_attr; BOOL bedit; /* get attachments */ for (i = 0; i < MAX_ATTACHMENTS; i++) { sprintf(str, "attachment%d", i); strcpy(att_file[i], getparam(str)); } reply_to[0] = 0; in_reply_to[0] = 0; date[0] = 0; encoding[0] = 0; bedit = FALSE; n_attr = 0; message_id = 0; /* retrieve attributes */ for (i = 0; i < MAX_PARAM; i++) { if (enumparam(i, name, value)) { if (strieq(name, "mirror_id")) message_id = atoi(value); else if (strieq(name, "entry_date")) strlcpy(date, value, sizeof(date)); else if (strieq(name, "reply_to")) strlcpy(reply_to, value, sizeof(reply_to)); else if (strieq(name, "in_reply_to")) strlcpy(in_reply_to, value, sizeof(in_reply_to)); else if (strieq(name, "encoding")) strlcpy(encoding, value, sizeof(encoding)); else if (!strieq(name, "cmd") && !strieq(name, "full_name") && !strieq(name, "user_email") && !strieq(name, "unm") && !strieq(name, "upwd") && !strieq(name, "wpwd") && strncmp(name, "attachment", 10) != 0) { strlcpy(attrib_name[n_attr], name, NAME_LENGTH); strlcpy(attrib_value[n_attr++], value, NAME_LENGTH); } } else break; } if (message_id == 0 || date[0] == 0) { show_error(loc("Invalid mirror_id or entry_date")); return; } /* check if message already exists */ for (i = 0; i < *lbs->n_el_index; i++) if (lbs->el_index[i].message_id == message_id) { bedit = TRUE; break; } message_id = el_submit(lbs, message_id, bedit, date, attrib_name, attrib_value, n_attr, getparam("text"), in_reply_to, reply_to, encoding, att_file, FALSE, NULL); if (message_id <= 0) { sprintf(str, loc("New entry cannot be written to directory \"%s\""), lbs->data_dir); strcat(str, "\n

"); strcat(str, loc("Please check that it exists and elogd has write access")); show_error(str); return; } sprintf(str, "%d", message_id); redirect(lbs, str); } /*------------------------------------------------------------------*/ void copy_to(LOGBOOK * lbs, int src_id, char *dest_logbook, int move, int orig_id) { int size, i, n, n_done, n_done_reply, n_reply, index, status, fh, source_id, message_id; char str[256], file_name[MAX_PATH_LENGTH], attrib[MAX_N_ATTR][NAME_LENGTH]; char date[80], *text, msg_str[32], in_reply_to[80], reply_to[MAX_REPLY_TO * 10], attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], encoding[80], locked_by[256], *buffer, list[MAX_N_ATTR][NAME_LENGTH]; LOGBOOK *lbs_dest; for (i = 0; lb_list[i].name[0]; i++) if (strieq(lb_list[i].name, dest_logbook)) break; if (!lb_list[i].name[0]) return; lbs_dest = &lb_list[i]; if (src_id) n = 1; else n = atoi(getparam("nsel")); text = malloc(TEXT_SIZE); n_done = n_done_reply = source_id = status = 0; for (index = 0; index < n; index++) { if (src_id) source_id = src_id; else { sprintf(str, "s%d", index); if (!isparam(str)) continue; source_id = atoi(getparam(str)); } /* get message */ size = TEXT_SIZE; status = el_retrieve(lbs, source_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to, reply_to, attachment, encoding, locked_by); if (status != EL_SUCCESS) { sprintf(msg_str, "%d", source_id); sprintf(str, loc("Entry %s cannot be read from logbook \"%s\""), msg_str, lbs->name); show_error(str); free(text); return; } if (orig_id == 0) { /* search message head */ while (atoi(in_reply_to) > 0) { source_id = atoi(in_reply_to); size = TEXT_SIZE; status = el_retrieve(lbs, source_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to, reply_to, attachment, encoding, locked_by); if (status != EL_SUCCESS) { sprintf(msg_str, "%d", source_id); sprintf(str, loc("Entry %s cannot be read from logbook \"%s\""), msg_str, lbs->name); show_error(str); free(text); return; } } } /* read attachments */ for (i = 0; i < MAX_ATTACHMENTS; i++) if (attachment[i][0]) { strlcpy(file_name, lbs->data_dir, sizeof(file_name)); strlcat(file_name, attachment[i], sizeof(file_name)); fh = open(file_name, O_RDONLY | O_BINARY); if (fh > 0) { lseek(fh, 0, SEEK_END); size = TELL(fh); lseek(fh, 0, SEEK_SET); buffer = malloc(size); if (buffer) read(fh, buffer, size); close(fh); /* stip date/time from file name */ strlcpy(file_name, attachment[i] + 14, NAME_LENGTH); el_submit_attachment(lbs_dest, file_name, buffer, size, attachment[i]); if (buffer) free(buffer); } else /* attachment is invalid */ attachment[i][0] = 0; } /* if called recursively (for threads), put in correct in_reply_to */ str[0] = 0; if (orig_id) sprintf(str, "%d", orig_id); /* submit in destination logbook without links, submit all attributes from the source logbook even if the destination has a differnt number of attributes */ message_id = el_submit(lbs_dest, 0, FALSE, date, attr_list, attrib, lbs->n_attr, text, str, "", encoding, attachment, TRUE, NULL); if (message_id <= 0) { sprintf(str, loc("New entry cannot be written to directory \"%s\""), lbs_dest->data_dir); strcat(str, "\n

"); strcat(str, loc("Please check that it exists and elogd has write access")); show_error(str); free(text); return; } n_done++; /* submit all replies */ n_reply = strbreak(reply_to, list, MAX_N_ATTR, ","); for (i = 0; i < n_reply; i++) { copy_to(lbs, atoi(list[i]), dest_logbook, move, message_id); } n_done_reply += n_reply; /* delete original message for move */ if (move && orig_id == 0) { el_delete_message(lbs, source_id, TRUE, NULL, TRUE, TRUE); /* check if this was the last message */ source_id = el_search_message(lbs, EL_NEXT, source_id, FALSE); /* if yes, force display of new last message */ if (source_id <= 0) source_id = el_search_message(lbs, EL_LAST, 0, FALSE); } } free(text); if (orig_id) return; /* display status message */ sprintf(str, "%d", source_id); show_standard_header(lbs, FALSE, loc("Copy ELog entry"), str); rsprintf(""); rsprintf("\n"); if (src_id) rsprintf ("\n", loc("Go to"), lbs->name, source_id, lbs->name); else { strcpy(str, getparam("lastcmd")); url_decode(str); rsprintf ("\n", loc("Go to"), lbs->name, str, lbs->name); } rsprintf ("\n", loc("Go to"), lbs_dest->name, lbs_dest->name); rsprintf("
\n"); if (n_done == 0) rsprintf(loc("No entry selected")); else { if (n_done == 1) rsprintf(loc("One entry")); else rsprintf(loc("%d messages"), n_done); if (n_done_reply) { rsprintf(" "); if (n_done == 1) rsprintf(loc("and its replies")); else rsprintf(loc("and their replies")); } rsprintf(" "); if (move) rsprintf(loc("moved successfully from \"%s\" to \"%s\""), lbs->name, lbs_dest->name); else rsprintf(loc("copied successfully from \"%s\" to \"%s\""), lbs->name, lbs_dest->name); } rsprintf("
%s %s
%s %s
%s %s
\n"); show_bottom_text(lbs); rsprintf("\r\n"); return; } /*------------------------------------------------------------------*/ void show_elog_message(LOGBOOK * lbs, char *dec_path, char *command) { int size, i, j, n, n_log, status, fh, length, message_error, index; int message_id, orig_message_id, format_flags[MAX_N_ATTR]; char str[1000], ref[256], file_name[256], attrib[MAX_N_ATTR][NAME_LENGTH]; char date[80], text[TEXT_SIZE], menu_str[1000], cmd[256], cmd_enc[256], orig_tag[80], reply_tag[MAX_REPLY_TO * 10], display[256], attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], encoding[80], locked_by[256], att[256], lattr[256], mid[80], menu_item[MAX_N_LIST][NAME_LENGTH], format[80], admin_user[80], slist[MAX_N_ATTR + 10][NAME_LENGTH], gattr[MAX_N_ATTR][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH], *p, lbk_list[MAX_N_LIST][NAME_LENGTH], comment[256], class_name[80], class_value[80], fl[8][NAME_LENGTH]; FILE *f; BOOL first, show_text; struct tm *pts; time_t ltime; message_id = atoi(dec_path); message_error = EL_SUCCESS; _current_message_id = message_id; /* check for guest access */ if (!getcfg(lbs->name, "Guest Menu commands", menu_str) || *getparam("unm") != 0) getcfg(lbs->name, "Menu commands", menu_str); /* default menu commands */ if (menu_str[0] == 0) { strcpy(menu_str, "Back, New, Edit, Delete, Reply, Find, "); if (getcfg(lbs->name, "Password file", str)) { strcat(menu_str, "Config, Logout, "); } else { strcat(menu_str, "Config, "); } strcat(menu_str, "Help"); } else { /* check for admin command */ n = strbreak(menu_str, menu_item, MAX_N_LIST, ","); menu_str[0] = 0; admin_user[0] = 0; getcfg(lbs->name, "Admin user", admin_user); for (i = 0; i < n; i++) { if (strcmp(menu_item[i], "Admin") == 0) { if (strstr(admin_user, getparam("unm")) == NULL) continue; } strcat(menu_str, menu_item[i]); if (i < n - 1) strcat(menu_str, ", "); } } /*---- check next/previous message -------------------------------*/ if (strieq(command, loc("Next")) || strieq(command, loc("Previous")) || strieq(command, loc("Last")) || strieq(command, loc("First"))) { orig_message_id = message_id; if (strieq(command, loc("Last"))) message_id = el_search_message(lbs, EL_LAST, 0, FALSE); if (strieq(command, loc("First"))) message_id = el_search_message(lbs, EL_FIRST, 0, FALSE); /* avoid display of "invalid id '0'", if "start page = 0?cmd=Last" */ if (!message_id) dec_path[0] = 0; first = TRUE; do { if (strieq(command, loc("Next"))) message_id = el_search_message(lbs, EL_NEXT, message_id, FALSE); if (strieq(command, loc("Previous"))) message_id = el_search_message(lbs, EL_PREV, message_id, FALSE); if (!first) { if (strieq(command, loc("First"))) message_id = el_search_message(lbs, EL_NEXT, message_id, FALSE); if (strieq(command, loc("Last"))) message_id = el_search_message(lbs, EL_PREV, message_id, FALSE); } else first = FALSE; if (message_id == 0) { if (strieq(command, loc("Next"))) message_error = EL_LAST_MSG; else message_error = EL_FIRST_MSG; message_id = orig_message_id; break; } size = sizeof(text); el_retrieve(lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, orig_tag, reply_tag, attachment, encoding, locked_by); /* check for locked attributes */ for (i = 0; i < lbs->n_attr; i++) { sprintf(lattr, "l%s", attr_list[i]); if (*getparam(lattr) == '1' && !strieq(getparam(attr_list[i]), attrib[i])) break; } if (i < lbs->n_attr) continue; /* check for attribute filter if not browsing */ if (!*getparam("browsing")) { for (i = 0; i < lbs->n_attr; i++) { if (*getparam(attr_list[i]) && !strieq(getparam(attr_list[i]), attrib[i])) break; } if (i < lbs->n_attr) continue; } sprintf(str, "%d", message_id); for (i = 0; i < lbs->n_attr; i++) { sprintf(lattr, "l%s", attr_list[i]); if (*getparam(lattr) == '1') { if (strchr(str, '?') == NULL) sprintf(str + strlen(str), "?%s=1", lattr); else sprintf(str + strlen(str), "&%s=1", lattr); } } redirect(lbs, str); return; } while (TRUE); } /*---- check for valid URL ---------------------------------------*/ if (dec_path[0] && atoi(dec_path) == 0) { sprintf(str, "Invalid URL: %s", dec_path); show_error(str); return; } /*---- get current message ---------------------------------------*/ if (message_id == 0) message_id = el_search_message(lbs, EL_LAST, 0, FALSE); status = 0; if (message_id) { size = sizeof(text); status = el_retrieve(lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, orig_tag, reply_tag, attachment, encoding, locked_by); if (status != EL_SUCCESS) message_error = status; else { if (_logging_level > 2) logf(lbs, "READ entry #%d", message_id); } } else message_error = EL_EMPTY; /*---- header ----*/ /* header */ if (status == EL_SUCCESS && message_error != EL_EMPTY) { str[0] = 0; if (getcfg(lbs->name, "Page Title", str)) { i = build_subst_list(lbs, slist, svalue, attrib, TRUE); sprintf(mid, "%d", message_id); add_subst_list(slist, svalue, "message id", mid, &i); add_subst_time(lbs, slist, svalue, "entry time", date, &i); strsubst(str, slist, svalue, i); strip_html(str); } else strcpy(str, "ELOG"); sprintf(ref, "%d", message_id); if (str[0]) show_standard_header(lbs, TRUE, str, ref); else show_standard_header(lbs, TRUE, lbs->name, ref); } else show_standard_header(lbs, TRUE, "", ""); /*---- title ----*/ show_standard_title(lbs->name, "", 0); /*---- menu buttons ----*/ rsprintf("\n"); rsprintf("\n"); rsprintf("\n\n"); /*---- next/previous buttons ----*/ if (!getcfg(lbs->name, "Enable browsing", str) || atoi(str) == 1) { rsprintf("\n"); } rsprintf("
\n"); n = strbreak(menu_str, menu_item, MAX_N_LIST, ","); for (i = 0; i < n; i++) { /* display menu item */ strcpy(cmd, menu_item[i]); /* only display allowed commands */ if (!is_user_allowed(lbs, cmd)) continue; if (strieq(cmd, "Copy to") || strieq(cmd, "Move to")) { if (getcfg(lbs->name, cmd, str)) { n_log = strbreak(str, lbk_list, MAX_N_LIST, ","); for (j = 0; j < n_log; j++) { strcpy(ref, lbk_list[j]); url_encode(ref, sizeof(ref)); strcpy(cmd_enc, loc(cmd)); url_encode(cmd_enc, sizeof(cmd_enc)); if (strieq(cmd, loc("Copy to"))) rsprintf (" %s \"%s\" |\n", lbs->name_enc, message_id, cmd_enc, ref, loc(cmd), lbk_list[j]); else rsprintf (" %s \"%s\" |\n", lbs->name_enc, message_id, cmd_enc, ref, loc(cmd), lbk_list[j]); } } else { /* put one link for each logbook except current one */ for (j = 0;; j++) { if (!enumgrp(j, str)) break; if (!is_logbook(str)) continue; if (strieq(str, lbs->name)) continue; strlcpy(ref, str, sizeof(ref)); url_encode(ref, sizeof(ref)); strcpy(cmd_enc, loc(cmd)); url_encode(cmd_enc, sizeof(cmd_enc)); if (strieq(cmd, "Copy to")) rsprintf (" %s \"%s\" |\n", lbs->name_enc, message_id, cmd_enc, ref, loc(cmd), str); else rsprintf (" %s \"%s\" |\n", lbs->name_enc, message_id, cmd_enc, ref, loc(cmd), str); } } } else { strcpy(str, loc(menu_item[i])); url_encode(str, sizeof(str)); if (i < n - 1) rsprintf(" %s |\n", message_id, str, loc(menu_item[i])); else rsprintf(" %s \n", message_id, str, loc(menu_item[i])); } } rsprintf("\n"); rsprintf("\n", loc("First entry")); rsprintf("\n", loc("Previous entry")); rsprintf("\n", loc("Next entry")); rsprintf("\n", loc("Last entry")); rsprintf("
\n\n"); /*---- menu text ----*/ if (getcfg(lbs->name, "menu text", str)) { FILE *f; char file_name[256], *buf; rsprintf("\n"); /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } f = fopen(file_name, "rb"); if (f != NULL) { fseek(f, 0, SEEK_END); size = TELL(fileno(f)); fseek(f, 0, SEEK_SET); buf = malloc(size + 1); fread(buf, 1, size, f); buf[size] = 0; fclose(f); rsputs(buf); } else rsprintf("

Error: file \"%s\" not found
", file_name); rsprintf(""); } /*---- message ----*/ if (message_error == EL_EMPTY) rsprintf("%s\n", loc("Logbook is empty")); else if (message_error == EL_NO_MSG) rsprintf("%s\n", loc("This entry has been deleted")); else { /* overall message table */ rsprintf ("\n"); /* check for locked attributes */ for (i = 0; i < lbs->n_attr; i++) { sprintf(lattr, "l%s", attr_list[i]); if (*getparam(lattr) == '1') break; } if (i < lbs->n_attr) sprintf(str, " %s \"%s = %s\"", loc("with"), attr_list[i], getparam(attr_list[i])); else str[0] = 0; if (message_error == EL_LAST_MSG) rsprintf("\n", loc("This is the last entry"), str); if (message_error == EL_FIRST_MSG) rsprintf("\n", loc("This is the first entry"), str); /* check for mail submissions */ if (*getparam("suppress")) { rsprintf("\n", loc("Email notification suppressed")); } else if (isparam("error")) { rsprintf("\n", getparam("error")); } else { for (i = 0;; i++) { sprintf(str, "mail%d", i); if (*getparam(str)) { if (i == 0) rsprintf("\n"); } /*---- display message ID ----*/ if (locked_by && locked_by[0]) { sprintf(str, "%s %s", loc("Entry is currently edited by"), locked_by); rsprintf("\n", str); } rsprintf("\n"); /*---- display attributes ----*/ /* retrieve attribute flags */ for (i = 0; i < lbs->n_attr; i++) { format_flags[i] = 0; sprintf(str, "Format %s", attr_list[i]); if (getcfg(lbs->name, str, format)) { n = strbreak(format, fl, 8, ","); if (n > 0) format_flags[i] = atoi(fl[0]); } } for (i = 0; i < lbs->n_attr; i++) { if (getcfg(lbs->name, "Password file", str) && getcfg(lbs->name, "Guest display", str) && !isparam("unm")) { n = strbreak(str, gattr, MAX_N_ATTR, ","); for (j = 0; j < n; j++) if (strieq(gattr[j], attr_list[i])) break; if (j == n) continue; } strcpy(class_name, "attribname"); strcpy(class_value, "attribvalue"); sprintf(str, "Format %s", attr_list[i]); if (getcfg(lbs->name, str, format), ",") { n = strbreak(format, fl, 8, ","); if (n > 1) strlcpy(class_name, fl[1], sizeof(class_name)); if (n > 2) strlcpy(class_value, fl[2], sizeof(class_value)); } if ((format_flags[i] & AFF_SAME_LINE) == 0) rsprintf("\n"); } rsputs("
%s %s
%s %s
%s
%s
"); rsprintf("%s %s
\n", loc("Email sent to"), getparam(str)); } else break; } if (i > 0) rsprintf("
\n"); rsprintf("%s
\n"); for (i = 0; i < lbs->n_attr; i++) { strencode2(str, attrib[i]); rsprintf("\n", attr_list[i], str); } /* browsing flag to distinguish "/../=" from browsing */ rsprintf("\n"); if (getcfg(lbs->name, "ID display", display)) { j = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list((char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "message id", str, &j); add_subst_time(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "entry time", date, &j); strsubst(display, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, j); } else sprintf(display, "%d", message_id); rsprintf("%s: %s\n", loc("Message ID"), display); /*---- display date ----*/ if (!getcfg(lbs->name, "Time format", format)) strcpy(format, DEFAULT_TIME_FORMAT); ltime = date_to_ltime(date); pts = localtime(<ime); strftime(str, sizeof(str), format, pts); rsprintf("    %s: %s\n", loc("Entry time"), str); /*---- link to original message or reply ----*/ if (message_error != EL_FILE_ERROR && (reply_tag[0] || orig_tag[0])) { if (orig_tag[0]) { sprintf(ref, "%s", orig_tag); rsprintf("    %s: ", loc("In reply to")); rsprintf("%s\n", ref, orig_tag); } if (reply_tag[0]) { rsprintf("    %s: ", loc("Reply to this")); p = strtok(reply_tag, ","); do { rsprintf("%s\n", p, p); p = strtok(NULL, ","); if (p) rsprintf("  \n"); } while (p); rsprintf("\n"); } } rsprintf("
"); sprintf(lattr, "l%s", attr_list[i]); rsprintf("\n", attr_list[i], class_value); else rsprintf("%s:\n", attr_list[i], class_value); } /* display image for icon */ else if (attr_flags[i] & AF_ICON) { rsprintf("%s:\n"); } else if ((attr_flags[i] & AF_MULTI) && (format_flags[i] & AFF_MULTI_LINE)) { rsprintf("%s:\n"); } else if (attr_flags[i] & AF_DATE) { if (!getcfg(lbs->name, "Date format", format)) strcpy(format, DEFAULT_DATE_FORMAT); ltime = atoi(attrib[i]); pts = localtime(<ime); if (ltime == 0) strcpy(str, "-"); else strftime(str, sizeof(str), format, pts); rsprintf("%s:\n", attr_list[i], class_value, str); } else { rsprintf("%s:\n"); } if (i == lbs->n_attr - 1 || (format_flags[i + 1] & AFF_SAME_LINE) == 0) rsprintf("
", class_name); if (getcfg(lbs->name, "Filtered browsing", str) && atoi(str) == 1) { if (*getparam(lattr) == '1') rsprintf(" ", lattr); else rsprintf (" ", lattr); } /* display checkbox for boolean attributes */ if (strieq(attr_options[i][0], "boolean")) { if (atoi(attrib[i]) == 1) rsprintf ("%s:\n", attr_list[i], class_value); if (attrib[i][0]) { sprintf(str, "Icon comment %s", attrib[i]); getcfg(lbs->name, str, comment); if (comment[0]) rsprintf("\"%s\"", attrib[i], comment); else rsprintf("\"%s\"", attrib[i], attrib[i]); } rsprintf(" \n", attr_list[i], class_value); /* separate options into individual lines */ strlcpy(str, attrib[i], sizeof(str)); p = strtok(str, "|"); while (p) { while (*p == ' ') p++; rsputs2(p); p = strtok(NULL, "|"); if (p) rsprintf("
"); } rsprintf("
%s \n", attr_list[i], class_value); sprintf(str, "Display %s", attr_list[i]); if (getcfg(lbs->name, str, display)) { j = build_subst_list(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, attrib, TRUE); sprintf(str, "%d", message_id); add_subst_list((char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "message id", str, &j); add_subst_time(lbs, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, "entry time", date, &j); strsubst(display, (char (*)[NAME_LENGTH]) slist, (char (*)[NAME_LENGTH]) svalue, j); } else strcpy(display, attrib[i]); if (is_html(display)) rsputs(display); else rsputs2(display); rsprintf(" 
\n"); rsputs("\n"); /*---- message text ----*/ show_text = !getcfg(lbs->name, "Show text", str) || atoi(str) == 1; if (getcfg(lbs->name, "Password file", str) && getcfg(lbs->name, "Guest display", str) && !isparam("unm")) { n = strbreak(str, gattr, MAX_N_ATTR, ","); for (j = 0; j < n; j++) if (strieq(gattr[j], "text")) break; if (j == n) show_text = FALSE; } if (show_text) { rsprintf("\n"); if (strieq(encoding, "plain")) { rsputs("
");
            rsputs2(text);
            rsputs("
"); } else rsputs(text); rsputs("\n"); for (index = 0; index < MAX_ATTACHMENTS; index++) { if (attachment[index][0] && strlen(attachment[index]) > 14) { for (i = 0; i < (int) strlen(attachment[index]); i++) att[i] = toupper(attachment[index][i]); att[i] = 0; /* determine size of attachment */ strlcpy(file_name, lbs->data_dir, sizeof(file_name)); strlcat(file_name, attachment[index], sizeof(file_name)); length = 0; fh = open(file_name, O_RDONLY | O_BINARY); if (fh > 0) { lseek(fh, 0, SEEK_END); length = TELL(fh); close(fh); } strcpy(str, attachment[index]); str[13] = 0; sprintf(ref, "%s/%s", str, attachment[index] + 14); url_encode(ref, sizeof(ref)); /* for file names with special characters like "+" */ /* overall table */ rsprintf ("\n"); rsprintf ("\n", loc("Attachment"), index + 1); rsprintf("
%s %d:%s\n", ref, attachment[index] + 14); rsprintf(" "); if (length < 1024) rsprintf("%d Bytes", length); else if (length < 1024 * 1024) rsprintf("%d kB", length / 1024); else rsprintf("%1.3lf MB", length / 1024.0 / 1024.0); rsprintf("
\n"); if (!getcfg(lbs->name, "Show attachments", str) || atoi(str) == 1) { if (strstr(att, ".GIF") || strstr(att, ".JPG") || strstr(att, ".JPEG") || strstr(att, ".PNG")) { rsprintf("\n"); rsprintf("\n", index + 1); rsprintf("", ref); rsprintf("\n\n"); } else { if (strstr(att, ".TXT") || strstr(att, ".ASC") || strchr(att, '.') == NULL) { /* display attachment */ rsprintf("\n"); /* anchor for references */ rsprintf("\n", index + 1); if (!strstr(att, ".HTML")) rsprintf("
");

                        strlcpy(file_name, lbs->data_dir, sizeof(file_name));
                        strlcat(file_name, attachment[index], sizeof(file_name));

                        f = fopen(file_name, "rt");
                        if (f != NULL) {
                           while (!feof(f)) {
                              str[0] = 0;
                              fgets(str, sizeof(str), f);

                              if (!strstr(att, ".HTML"))
                                 rsputs2(str);
                              else
                                 rsputs(str);
                           }
                           fclose(f);
                        }

                        if (!strstr(att, ".HTML"))
                           rsprintf("
"); rsprintf("\n"); rsprintf("\n"); } } } } } } } /* overall table (class "frame" from show_standard_header) */ rsprintf("\r\n\r\n"); show_bottom_text(lbs); rsprintf("\r\n"); } /*------------------------------------------------------------------*/ BOOL check_password(LOGBOOK * lbs, char *name, char *password, char *redir) { char str[256]; /* get password from configuration file */ if (getcfg(lbs->name, name, str)) { if (strcmp(password, str) == 0) return TRUE; if (!isparam("wpwd") && password[0]) { strlcpy(str, redir, sizeof(str)); if (strchr(str, '?')) strlcat(str, "&wpwd=1", sizeof(str)); else strlcat(str, "?wpwd=1", sizeof(str)); redirect(lbs, str); return FALSE; } /* show web password page */ show_standard_header(lbs, FALSE, loc("ELOG password"), NULL); rsprintf(""); if (isparam("wpwd")) rsprintf("\n", loc("Wrong password")); rsprintf("\n", loc("Please enter password to obtain write access")); rsprintf ("\n"); } else { rsprintf("%s\n", loc("Please enter password to obtain administration access")); rsprintf ("\n"); } rsprintf ("", loc("Submit")); rsprintf("
%s!
\n"); /* define hidden fields for current destination */ if (redir[0]) rsprintf("\n", redir); if (strcmp(name, "Write password") == 0) { rsprintf("%s
\n"); show_bottom_text(lbs); rsprintf("\r\n"); return FALSE; } else return TRUE; } /*------------------------------------------------------------------*/ int get_user_line(char *logbook_name, char *user, char *password, char *full_name, char *email, char *email_notify) { char str[256], line[256], file_name[256], *p; FILE *f; int i, fd; if (password) password[0] = 0; if (full_name) full_name[0] = 0; if (email) email[0] = 0; if (email_notify) email_notify[0] = 0; getcfg(logbook_name, "Password file", str); if (!str[0]) return 1; if (str[0] == DIR_SEPARATOR || str[1] == ':') strlcpy(file_name, str, sizeof(file_name)); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } f = fopen(file_name, "r"); /* if password file doen't exist, try to create it */ if (f == NULL) { fd = open(file_name, O_CREAT | O_RDWR, 0600); if (fd < 0) return 3; close(fd); f = fopen(file_name, "r"); } if (f != NULL) { if (!user[0]) { fclose(f); return 1; } while (!feof(f)) { line[0] = 0; fgets(line, sizeof(line), f); if (line[0] == ';' || line[0] == '#' || line[0] == 0) continue; strcpy(str, line); if (strchr(str, ':')) *strchr(str, ':') = 0; if (strcmp(str, user) == 0) break; } fclose(f); if (strcmp(str, user) != 0) return 2; /* if user found, retrieve other info */ p = line; for (i = 0; i < 4; i++) { if (strchr(p, ':') == NULL) break; p = strchr(p, ':') + 1; while (*p && *p == ' ') p++; strlcpy(str, p, sizeof(str)); if (strchr(str, ':')) *strchr(str, ':') = 0; while (str[strlen(str) - 1] == ' ' || str[strlen(str) - 1] == '\r' || str[strlen(str) - 1] == '\n') str[strlen(str) - 1] = 0; if (i == 0 && password) strcpy(password, str); else if (i == 1 && full_name) strcpy(full_name, str); else if (i == 2 && email) strcpy(email, str); else if (i == 3 && email_notify) strcpy(email_notify, str); } return 1; } else { if (user[0]) return 3; else return 1; } } /*------------------------------------------------------------------*/ BOOL enum_user_line(LOGBOOK * lbs, int n, char *user) { char str[256], line[256], file_name[256]; FILE *f; int i; getcfg(lbs->name, "Password file", str); if (!str[0]) return FALSE; if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } f = fopen(file_name, "r"); i = 0; if (f != NULL) { while (!feof(f)) { line[0] = 0; fgets(line, sizeof(line), f); if (line[0] == ';' || line[0] == '#' || line[0] == 0) continue; if (strchr(line, ':') == NULL) continue; strcpy(str, line); if (strchr(str, ':')) *strchr(str, ':') = 0; if (i == n) { strcpy(user, str); fclose(f); return TRUE; } i++; } fclose(f); } return FALSE; } /*------------------------------------------------------------------*/ BOOL check_login_user(LOGBOOK * lbs, char *user) { int i, n; char str[1000]; char list[MAX_N_LIST][NAME_LENGTH]; if (getcfg(lbs->name, "Login user", str) && user[0]) { n = strbreak(str, list, MAX_N_LIST, ","); for (i = 0; i < n; i++) if (strcmp(user, list[i]) == 0) break; if (i == n) return FALSE; } return TRUE; } /*------------------------------------------------------------------*/ BOOL check_user_password(LOGBOOK * lbs, char *user, char *password, char *redir) { char status, str[1000], upwd[256], full_name[256], email[256]; if (lbs == NULL) status = get_user_line("global", user, upwd, full_name, email, NULL); else status = get_user_line(lbs->name, user, upwd, full_name, email, NULL); /* check for logout */ if (isparam("LO")) { /* remove cookies */ set_login_cookies(lbs, "", ""); return FALSE; } /* check for "forgot password" */ if (isparam("cmd") && strcmp(getparam("cmd"), loc("Forgot")) == 0) { show_forgot_pwd_page(lbs); return FALSE; } /* display error message for invalid user */ if (isparam("iusr")) { /* header */ show_html_header(NULL, FALSE, "ELOG error", TRUE); rsprintf("
\n"); rsprintf(""); sprintf(str, loc("User \"%s\" has no access to logbook \"%s\""), getparam("iusr"), lbs->name); rsprintf("\n", str); rsprintf("", loc("Login as different user")); rsprintf("", loc("Goto logbook selection page")); rsprintf("
%s
"); rsprintf("%s
"); rsprintf("%s
\n"); rsprintf("
\n"); return FALSE; } if (!check_login_user(lbs, user)) { sprintf(str, "?iusr=%s", user); redirect(lbs, str); return FALSE; } if (status == 1) { if (user[0] && strcmp(password, upwd) == 0) { setparam("full_name", full_name); setparam("user_email", email); return TRUE; } if (!isparam("wpwd") && password[0]) { redirect(lbs, "?wpwd=1"); return FALSE; } /* show login password page */ sprintf(str, "ELOG %s", loc("Login")); show_html_header(lbs, TRUE, str, TRUE); /* set focus on name field */ rsprintf("\n"); rsprintf("
\n\n"); /* define hidden fields for current destination */ rsprintf("\n", redir); rsprintf(""); if (isparam("wpwd")) rsprintf("\n", loc("Wrong password")); if (isparam("wusr")) { sprintf(str, loc("Invalid user name \"%s\""), getparam("wusr")); rsprintf("\n", str); } rsprintf("\n", loc("Please login")); rsprintf("\n", loc("Username")); rsprintf ("\n", getparam("unm")); rsprintf("\n", loc("Password")); rsprintf ("\n"); if (!getcfg(lbs->name, "Login expiration", str) || atoi(str) > 0) { rsprintf("\n", loc("Remember me on this computer")); } rsprintf ("", str, loc("Register as new user")); } rsprintf ("", loc("Submit")); rsprintf("
%s!
%s!
%s
%s:
%s:
"); rsprintf("\n"); rsprintf("%s
%s", loc("Forgot"), loc("Forgot password?")); if (getcfg(lbs->name, "Self register", str) && atoi(str) > 0) { strcpy(str, loc("New user")); url_encode(str, sizeof(str)); rsprintf("      %s
\n"); rsprintf ("
ELOG V%s
", VERSION); rsprintf("\r\n"); return FALSE; } else { if (status == 2) { sprintf(str, "?wusr=%s", user); setparam("redir", str); /* remove remaining cookies */ set_login_cookies(lbs, "", ""); } else { getcfg(lbs->name, "Password file", full_name); sprintf(str, loc("Cannot open file %s"), full_name); show_error(str); } return FALSE; } } /*------------------------------------------------------------------*/ int node_contains(LBLIST pn, char *logbook) { int i; for (i = 0; i < pn->n_members; i++) { /* check if logbook in this group */ if (strieq(pn->member[i]->name, logbook)) return 1; /* check if loogbook is in subgroups */ if (pn->member[i]->n_members > 0 && node_contains(pn->member[i], logbook)) return 1; } return 0; } /*------------------------------------------------------------------*/ void show_logbook_node(LBLIST plb, LBLIST pparent, int level, int btop) { int i, index, j, expand, message_id; char str[10000], date[256], ref[256], slist[MAX_N_ATTR + 10][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH], mid[80]; if (plb->n_members > 0) { expand = 0; if (isparam("gexp")) { if (strieq(plb->name, getparam("gexp")) || node_contains(plb, getparam("gexp")) || strieq(getparam("gexp"), "all")) expand = 1; } /* do not display top groups */ if (!plb->is_top) { rsprintf(""); for (i = 0; i < level; i++) rsprintf(" \n"); rsprintf("", 13 - level); for (i = 0; i < level; i++) rsprintf("  "); if (expand) { if (pparent == NULL) sprintf(ref, "."); else sprintf(ref, "?gexp=%s", pparent->name); rsprintf("- %s ", ref, plb->name); } else { sprintf(ref, "?gexp=%s", plb->name); rsprintf("+ %s ", ref, plb->name); } rsprintf("\n"); } if (plb->is_top || expand) for (i = 0; i < plb->n_members; i++) show_logbook_node(plb->member[i], plb->is_top ? NULL : plb, level + 1, btop); } else { if (!getcfg(plb->name, "Hidden", str) || atoi(str) == 0) { /* search logbook in list */ for (index = 0; lb_list[index].name[0]; index++) if (strieq(plb->name, lb_list[index].name)) break; if (!lb_list[index].name[0]) return; rsprintf(""); for (j = 0; j < level; j++) rsprintf(" \n"); rsprintf("", 10 - level); /* add one ".." if we are under top group */ if (btop) rsprintf("%s", lb_list[index].name_enc, lb_list[index].name); else rsprintf("%s", lb_list[index].name_enc, lb_list[index].name); if (getcfg(lb_list[index].name, "Read password", str) || (getcfg(lb_list[index].name, "Password file", str) && !getcfg(lb_list[index].name, "Guest menu commands", str))) rsprintf("  "); rsprintf("
\n"); str[0] = 0; getcfg(lb_list[index].name, "Comment", str); rsprintf("%s\n", str); rsprintf(""); rsprintf("%d", *lb_list[index].n_el_index); rsprintf("\n"); rsprintf(""); if (*lb_list[index].n_el_index == 0) rsprintf("-"); else { char attrib[MAX_N_ATTR][NAME_LENGTH]; lb_list[index].n_attr = scan_attributes(lb_list[index].name); message_id = el_search_message(&lb_list[index], EL_LAST, 0, FALSE); el_retrieve(&lb_list[index], message_id, date, attr_list, attrib, lb_list[index].n_attr, NULL, 0, NULL, NULL, NULL, NULL, NULL); if (!getcfg(lb_list[index].name, "Last submission", str)) { sprintf(str, "$entry time"); for (i = 0; i < lb_list[index].n_attr; i++) if (strieq(attr_list[i], "Author")) break; if (i < lb_list[index].n_attr) sprintf(str + strlen(str), " %s $author", loc("by")); } j = build_subst_list(&lb_list[index], slist, svalue, attrib, TRUE); sprintf(mid, "%d", message_id); add_subst_list(slist, svalue, "message id", mid, &j); add_subst_time(&lb_list[index], slist, svalue, "entry time", date, &j); strsubst(str, slist, svalue, j); rsputs(str); } rsprintf("\n"); } } } /*------------------------------------------------------------------*/ void show_selection_page() { int i, j, show_title; char str[NAME_LENGTH], file_name[256]; LBLIST phier; /* check for Guest Selection Page */ if (getcfg("global", "Guest Selection Page", str) && !(isparam("unm") && isparam("upwd"))) { /* check for URL */ if (strstr(str, "http://")) { redirect(NULL, str); return; } /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strlcpy(file_name, str, sizeof(file_name)); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } send_file_direct(file_name); return; } /* top group present and no top group in URL -> abort connection */ if (exist_top_group() && getcfg_topgroup() == NULL) return; /* if selection page protected, check password */ if (getcfg("global", "password file", str) && getcfg("global", "protect selection page", str) && atoi(str) == 1) if (!check_user_password(NULL, getparam("unm"), getparam("upwd"), "")) return; if (getcfg("global", "Page Title", str)) { strip_html(str); show_html_header(NULL, TRUE, str, TRUE); } else show_html_header(NULL, TRUE, "ELOG Logbook Selection", TRUE); rsprintf("\n\n"); rsprintf("\n"); rsprintf("\n"); if (getcfg("global", "mirror server", str)) { /* only admin user sees synchronization link */ if (!getcfg("global", "Admin user", str) || strcmp(str, getparam("unm")) == 0) { rsprintf("\n"); rsprintf("\n", loc("Synchronize all logbooks")); rsprintf("\n"); } } phier = get_logbook_hierarchy(); show_title = 0; if (getcfg_topgroup()) { for (i = 0; i < phier->n_members; i++) if (strieq(getcfg_topgroup(), phier->member[i]->name)) { if (phier->member[i]->n_members == 0) show_title = 1; else for (j = 0; j < phier->member[i]->n_members; j++) if (phier->member[i]->member[j]->n_members == 0) show_title = 1; break; } } else for (i = 0; i < phier->n_members; i++) { if (phier->member[i]->n_members == 0) show_title = 1; else for (j = 0; j < phier->member[i]->n_members; j++) if (phier->member[i]->member[j]->n_members == 0) show_title = 1; } if (isparam("gexp")) show_title = 1; if (show_title) { rsprintf("\n"); rsprintf("\n", loc("Logbook")); rsprintf("\n", loc("Entries")); rsprintf("\n", loc("Last submission")); rsprintf("\n"); } else { rsprintf("\n"); rsprintf("\n", loc("Expand all")); rsprintf("\n"); } if (getcfg_topgroup()) { for (i = 0; i < phier->n_members; i++) if (strieq(getcfg_topgroup(), phier->member[i]->name)) { show_logbook_node(phier->member[i], NULL, -1, 1); break; } } else for (i = 0; i < phier->n_members; i++) show_logbook_node(phier->member[i], NULL, 0, 0); free_logbook_hierarchy(phier); rsprintf("
\n"); if (getcfg("global", "Welcome title", str)) { rsputs(str); } else { rsprintf("%s.
\n", loc("Several logbooks are defined on this host")); rsprintf("%s:\n", loc("Please select the one to connect to")); } rsprintf("
\n"); rsprintf("%s
%s%s%s
\n"); rsprintf("%s
\n"); rsprintf("\r\n\r\n"); } /*------------------------------------------------------------------*/ void get_password(char *password) { static char last_password[32]; if (strncmp(password, "set=", 4) == 0) strcpy(last_password, password + 4); else strcpy(password, last_password); } /*------------------------------------------------------------------*/ int do_self_register(LOGBOOK * lbs, char *command) /* evaluate self-registration commands */ { char str[256]; /* display new user page if "self register" is clicked */ if (strieq(command, loc("New user"))) { show_new_user_page(lbs); return 0; } /* save user info if "save" is pressed */ if (strieq(command, loc("Save")) && isparam("new_user_name") && !isparam("config")) { if (!save_user_config(lbs, getparam("new_user_name"), TRUE, FALSE)) return 0; if (lbs) sprintf(str, "../%s/", lbs->name_enc); else sprintf(str, "."); redirect(lbs, str); return 0; } /* display account request notification */ if (strieq(command, loc("Requested"))) { show_standard_header(lbs, FALSE, loc("ELOG registration"), ""); rsprintf(""); rsprintf("
\n"); rsprintf(loc ("Your request has been forwarded to the administrator. You will be notified by email upon activation of your new account.")); rsprintf("
\n"); show_bottom_text(lbs); rsprintf("\n"); return 0; } /* indicate continue */ return 1; } /*------------------------------------------------------------------*/ void show_day(char *css_class, char *day) { if (day[0]) { rsprintf("%s\n", day); } else { /* empty cell */ rsprintf(" \n", css_class); } } void show_calendar(LOGBOOK * lbs) { int i, j, cur_mon, cur_day, cur_year, today_day, today_mon, today_year; time_t now, stime; struct tm *ts; char str[256], index[10]; time(&now); ts = localtime(&now); today_mon = ts->tm_mon + 1; today_day = ts->tm_mday; today_year = ts->tm_year + 1900; if (isparam("m") && isparam("y")) { cur_mon = atoi(getparam("m")); cur_year = atoi(getparam("y")); cur_day = -1; ts->tm_mday = 1; ts->tm_mon = cur_mon - 1; ts->tm_year = cur_year - 1900; mktime(ts); } else { cur_mon = ts->tm_mon + 1; cur_day = ts->tm_mday; cur_year = ts->tm_year + 1900; } if (isparam("i")) strcpy(index, getparam("i")); else strcpy(index, "1"); show_html_header(lbs, FALSE, loc("Calendar"), TRUE); rsprintf("\n"); rsprintf("\n", index); rsprintf("\n", cur_year); rsprintf("\n\n"); rsprintf(""); rsprintf("\n"); for (i = 0; i < 7; i++) { ts = localtime(&stime); strftime(str, sizeof(str), "%a", ts); rsprintf("\n", str); stime += 3600 * 24; } rsprintf("\n"); stime -= 3600 * 24 * 7; ts = localtime(&stime); for (i = 0; i < 6; i++) { rsprintf("\n"); for (j = 0; j < 7; j++) { if (ts->tm_mon + 1 == cur_mon) sprintf(str, "%d", ts->tm_mday); else strcpy(str, ""); if (ts->tm_mday == today_day && ts->tm_mon + 1 == today_mon && ts->tm_year + 1900 == today_year) show_day("calcurday", str); else { if (j == 0) show_day("calsun", str); else if (j == 6) show_day("calsat", str); else show_day("calday", str); } stime += 3600 * 24; ts = localtime(&stime); } rsprintf("\n"); if (ts->tm_mon + 1 != cur_mon) break; } rsprintf("\n"); } /*------------------------------------------------------------------*/ void interprete(char *lbook, char *path) /********************************************************************\ Routine: interprete Purpose: Interprete parametersand generate HTML output. Input: char *path Message path _param/_value array accessible via getparam() \********************************************************************/ { int status, i, j, n, index, lb_index, message_id; char exp[80], list[1000], section[256], str[NAME_LENGTH], str2[NAME_LENGTH], enc_pwd[80], file_name[256], command[80], ref[256], enc_path[256], dec_path[256], logbook[256], logbook_enc[256], *experiment, *value, *group, css[256], *pfile, attachment[MAX_PATH_LENGTH]; BOOL global; LOGBOOK *lbs; FILE *f; /* encode path for further usage */ strcpy(dec_path, path); url_decode(dec_path); strcpy(enc_path, dec_path); url_encode(enc_path, sizeof(enc_path)); strcpy(command, getparam("cmd")); experiment = getparam("exp"); value = getparam("value"); group = getparam("group"); index = atoi(getparam("index")); if (getcfg(lbook, "Logging Level", str)) _logging_level = atoi(str); else _logging_level = 2; set_condition(""); /* if experiment given, use it as logbook (for elog!) */ if (experiment && experiment[0]) { strcpy(logbook_enc, experiment); strcpy(logbook, experiment); url_decode(logbook); /* check if logbook exists */ for (i = 0;; i++) { if (!enumgrp(i, str)) break; if (strieq(logbook, str)) break; } if (!strieq(logbook, str)) { sprintf(str, "Error: logbook \"%s\" not defined in elogd.cfg", logbook); show_error(str); return; } } else { strcpy(logbook_enc, lbook); strcpy(logbook, lbook); url_decode(logbook); } /* check for top group */ setcfg_topgroup(""); sprintf(str, "Top group %s", logbook); if (getcfg("global", str, list)) { setcfg_topgroup(logbook); logbook[0] = 0; } /* check if new logbook */ for (i = j = 0;; i++) { if (!enumgrp(i, str)) break; if (is_logbook(str)) { /* redo index if logbooks in cfg file do not match lb_list */ if (!strieq(str, lb_list[j++].name)) { el_index_logbooks(TRUE); break; } } } /* check for deleted logbook */ if (lb_list[j].name[0] != 0) el_index_logbooks(TRUE); /*---- direct commands (registration etc) ----*/ if (!logbook[0]) { /* check for self register */ if (getcfg(group, "Self register", str) && atoi(str) > 0) { if (!do_self_register(NULL, getparam("cmd"))) return; } /* check for activate */ if (strieq(getparam("cmd"), "Activate")) { if (!save_user_config(NULL, getparam("new_user_name"), TRUE, TRUE)) return; setparam("cfg_user", getparam("new_user_name")); show_config_page(NULL); return; } /* check for save after activate */ if (strieq(getparam("cmd"), loc("Save"))) { if (isparam("config")) { /* change existing user */ if (!save_user_config(NULL, getparam("config"), FALSE, FALSE)) return; } redirect(NULL, "."); return; } /* check for password recovery */ if (isparam("cmd") || isparam("newpwd")) { if (strieq(getparam("cmd"), loc("Change password")) || isparam("newpwd")) { show_change_pwd_page(NULL); return; } } /* if data from login screen, evaluate it and set cookies */ if (*getparam("uname") && getparam("upassword")) { /* check if password correct */ do_crypt(getparam("upassword"), enc_pwd); /* log logins */ logf(NULL, "LOGIN user \"%s\" (attempt) for logbook selection page", getparam("uname")); if (isparam("redir")) strcpy(str, getparam("redir")); else strcpy(str, getparam("cmdline")); if (!check_user_password(NULL, getparam("uname"), enc_pwd, str)) return; logf(NULL, "LOGIN user \"%s\" (success)", getparam("uname")); /* set cookies */ set_login_cookies(NULL, getparam("uname"), enc_pwd); return; } /* check for global selection page if no logbook given */ if (!logbook[0] && getcfg("global", "Selection page", str)) { /* check for URL */ if (strstr(str, "http://")) { redirect(NULL, str); return; } /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strlcpy(file_name, str, sizeof(file_name)); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } send_file_direct(file_name); return; } /* check for global synchronization */ if (strieq(command, "Synchronize")) { synchronize(NULL, FALSE); return; } } /* count logbooks */ for (n = 0; lb_list[n].name[0]; n++); /* if no logbook given, display logbook selection page */ if (!logbook[0] && !path[0]) { if (n > 1) { show_selection_page(NULL); return; } strcpy(logbook_enc, logbook); url_encode(logbook_enc, sizeof(logbook_enc)); } /* get logbook from list */ for (i = 0; lb_list[i].name[0]; i++) if (strieq(logbook, lb_list[i].name)) break; lbs = &lb_list[i]; /* set top level group for logbook */ if (lbs->top_group[0]) setcfg_topgroup(lbs->top_group); /* get theme for logbook */ if (getcfg(logbook, "Theme", str)) strlcpy(theme_name, str, sizeof(theme_name)); else strlcpy(theme_name, "default", sizeof(theme_name)); lb_index = i; lbs = lb_list + i; lbs->n_attr = scan_attributes(lbs->name); if (*getparam("wpassword")) { /* check if password correct */ do_crypt(getparam("wpassword"), enc_pwd); if (!check_password(lbs, "Write password", enc_pwd, getparam("redir"))) return; rsprintf("HTTP/1.1 302 Found\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } global = getcfg("global", "Write password", str); /* get optional expriation from configuration file */ getcfg(logbook, "Write password expiration", exp); /* set "wpwd" cookie */ set_cookie(lbs, "wpwd", enc_pwd, global, exp); /* redirect according to "redir" parameter */ set_redir(lbs, getparam("redir")); return; } if (*getparam("apassword")) { /* check if password correct */ do_crypt(getparam("apassword"), enc_pwd); if (!check_password(lbs, "Admin password", enc_pwd, getparam("redir"))) return; rsprintf("HTTP/1.1 302 Found\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); if (use_keepalive) { rsprintf("Connection: Keep-Alive\r\n"); rsprintf("Keep-Alive: timeout=60, max=10\r\n"); } global = getcfg("global", "Admin password", str); /* get optional expriation from configuration file */ getcfg(logbook, "Admin password expiration", exp); /* set "apwd" cookie */ set_cookie(lbs, "apwd", enc_pwd, global, exp); /* redirect according to "redir" parameter */ set_redir(lbs, getparam("redir")); return; } if (*getparam("uname") && getparam("upassword")) { /* check if password correct */ do_crypt(getparam("upassword"), enc_pwd); /* log logins */ logf(lbs, "LOGIN user \"%s\" (attempt)", getparam("uname")); if (isparam("redir")) strcpy(str, getparam("redir")); else strcpy(str, getparam("cmdline")); if (!check_user_password(lbs, getparam("uname"), enc_pwd, str)) return; logf(lbs, "LOGIN user \"%s\" (success)", getparam("uname")); /* set cookies */ set_login_cookies(lbs, getparam("uname"), enc_pwd); return; } /* if password file given, check password and user name */ if (getcfg(logbook, "Password file", str)) { /* get current CSS */ strlcpy(css, "default.css", sizeof(css)); if (lbs != NULL && getcfg(lbs->name, "CSS", str)) strlcpy(css, str, sizeof(css)); else if (lbs == NULL && getcfg("global", "CSS", str)) strlcpy(css, str, sizeof(css)); /* check if guest access */ if (!(getcfg(lbs->name, "Guest menu commands", str) && *getparam("unm") == 0 && !isparam("wpwd") && !isparam("wusr"))) { if (strcmp(path, css) != 0) { /* if no guest menu commands but self register, evaluate new user commands */ if (getcfg(lbs->name, "Self register", str) && atoi(str) > 0) { if (!do_self_register(lbs, command)) return; } if (!check_user_password (lbs, getparam("unm"), getparam("upwd"), getparam("cmdline"))) return; } } } if (strieq(command, loc("Login"))) { check_user_password(lbs, "", "", path); return; } if (strieq(command, loc("New")) || strieq(command, loc("Edit")) || strieq(command, loc("Reply")) || strieq(command, loc("Delete")) || strieq(command, loc("Upload")) || strieq(command, loc("Submit"))) { sprintf(str, "%s?cmd=%s", path, command); if (!check_password(lbs, "Write password", getparam("wpwd"), str)) return; } if (strieq(command, loc("Delete")) || strieq(command, loc("Config")) || strieq(command, loc("Copy to")) || strieq(command, loc("Move to"))) { sprintf(str, "%s?cmd=%s", path, command); if (!check_password(lbs, "Admin password", getparam("apwd"), str)) return; } /* check for "Back" button */ if (strieq(command, loc("Back")) && getcfg(lbs->name, "Back to main", str) && atoi(str) == 1) { redirect(lbs, "../"); return; } if (strieq(command, loc("Back"))) { if (isparam("edit_id")) { /* unlock message */ el_lock_message(lbs, atoi(getparam("edit_id")), NULL); /* redirect to message */ sprintf(str, "../%s/%s", logbook_enc, getparam("edit_id")); } else sprintf(str, "../%s/", logbook_enc); redirect(lbs, str); return; } /* check for "Cancel" button */ if (strieq(command, loc("Cancel"))) { sprintf(str, "../%s/%s", logbook_enc, path); redirect(lbs, str); return; } /* check for "Last n*2 Entries" */ strcpy(str, getparam("last")); if (strchr(str, ' ')) { i = atoi(strchr(str, ' ')); sprintf(str, "last%d", i); if (isparam("mode")) sprintf(str + strlen(str), "?mode=%s", getparam("mode")); redirect(lbs, str); return; } strcpy(str, getparam("past")); if (strchr(str, ' ')) { i = atoi(strchr(str, ' ')); sprintf(str, "past%d", i); redirect(lbs, str); return; } /* check for lastxx and pastxx and listxx */ if (strncmp(path, "past", 4) == 0 && isdigit(path[4]) && *getparam("cmd") == 0) { show_elog_list(lbs, atoi(path + 4), 0, 0, NULL); return; } if (strncmp(path, "last", 4) == 0 && strstr(path, ".gif") == NULL && (!isparam("cmd") || strieq(getparam("cmd"), loc("Select"))) && !isparam("newpwd")) { show_elog_list(lbs, 0, atoi(path + 4), 0, NULL); return; } if (strncmp(path, "page", 4) == 0 && *getparam("cmd") == 0) { if (!path[4]) show_elog_list(lbs, 0, 0, -1, NULL); else show_elog_list(lbs, 0, 0, atoi(path + 4), NULL); return; } /*---- check if file requested -----------------------------------*/ /* skip elog message id in front of possible attachment */ pfile = dec_path; if (strchr(pfile, '/') && pfile[13] != '/' && isdigit(pfile[0])) pfile = strchr(pfile, '/') + 1; if ((strlen(pfile) > 13 && pfile[6] == '_' && pfile[13] == '_') || (strlen(pfile) > 13 && pfile[6] == '_' && pfile[13] == '/') || strstr(pfile, ".gif") || strstr(pfile, ".ico") || strstr(pfile, ".jpg") || strstr(pfile, ".jpeg") || strstr(pfile, ".png") || strstr(pfile, ".css") || strstr(pfile, ".js")) { if ((strlen(pfile) > 13 && pfile[6] == '_' && pfile[13] == '_') || (strlen(pfile) > 13 && pfile[6] == '_' && pfile[13] == '/')) { if (pfile[13] == '/') pfile[13] = '_'; /* file from data directory requested */ strlcpy(file_name, lbs->data_dir, sizeof(file_name)); strlcat(file_name, pfile, sizeof(file_name)); } else { /* file from theme directory requested */ strlcpy(file_name, resource_dir, sizeof(file_name)); if (file_name[0] && file_name[strlen(file_name) - 1] != DIR_SEPARATOR) strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name)); strlcat(file_name, "themes", sizeof(file_name)); strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name)); if (theme_name[0]) { strlcat(file_name, theme_name, sizeof(file_name)); strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name)); } strlcat(file_name, pfile, sizeof(file_name)); } send_file_direct(file_name); return; } /* from here on, logbook must be valid */ if (!logbook[0]) { show_selection_page(NULL); return; } /*---- check if attachment requested -----------------------------*/ if (strchr(dec_path, '/')) { message_id = atoi(dec_path); n = atoi(strchr(dec_path, '/') + 1) - 1; status = el_retrieve_attachment(lbs, message_id, n, attachment); if (status != EL_SUCCESS || n >= MAX_ATTACHMENTS) { sprintf(str, "Attachment #%d of entry #%d not found", n + 1, message_id); show_error(str); } else { redirect(lbs, attachment); } return; } /* check for new syntax in elogd.cfg */ if (getcfg(lbs->name, "Types", str)) { show_upgrade_page(lbs); return; } /* correct for image buttons */ if (*getparam("cmd_first.x")) strcpy(command, loc("First")); if (*getparam("cmd_previous.x")) strcpy(command, loc("Previous")); if (*getparam("cmd_next.x")) strcpy(command, loc("Next")); if (*getparam("cmd_last.x")) strcpy(command, loc("Last")); /* check if command allowed for current user */ if (command[0] && !is_user_allowed(lbs, command)) { sprintf(str, loc ("Error: Command \"%s\" is not allowed for user \"%s\""), command, getparam("full_name")); show_error(str); return; } /* check if command in menu list */ if (!is_command_allowed(lbs, command)) { sprintf(str, loc("Error: Command \"%s\" not allowed"), command); show_error(str); return; } /*---- check for various commands --------------------------------*/ if (strieq(command, loc("Help"))) { if (getcfg(lbs->name, "Help URL", str)) { /* if file is given, add '/' to make absolute path */ if (strchr(str, '/') == NULL) sprintf(ref, "/%s", str); else strcpy(ref, str); redirect(lbs, ref); return; } /* send local help file */ strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, "eloghelp_", sizeof(file_name)); if (getcfg("global", "Language", str)) { str[2] = 0; strlcat(file_name, str, sizeof(file_name)); } else strlcat(file_name, "en", sizeof(file_name)); strlcat(file_name, ".html", sizeof(file_name)); f = fopen(file_name, "r"); if (f == NULL) redirect(lbs, "http://midas.psi.ch/elog/eloghelp_en.html"); else { fclose(f); send_file_direct(file_name); } return; } if (strieq(command, loc("New"))) { show_edit_form(lbs, 0, FALSE, FALSE, FALSE, FALSE); return; } message_id = atoi(dec_path); if (strieq(command, loc("Upload"))) { show_edit_form(lbs, atoi(getparam("edit_id")), FALSE, TRUE, TRUE, FALSE); return; } /* check for deletion of attachments */ for (i = 0; i < MAX_ATTACHMENTS; i++) { sprintf(str, "delatt%d", i); if (isparam(str)) { sprintf(str, "attachment%d", i); strlcpy(file_name, getparam(str), sizeof(file_name)); el_delete_attachment(lbs, file_name); /* re-order attachments */ for (j = i; j < MAX_ATTACHMENTS; j++) { sprintf(str, "attachment%d", j + 1); if (isparam(str)) strlcpy(file_name, getparam(str), sizeof(file_name)); else file_name[0] = 0; sprintf(str, "attachment%d", j); if (file_name[0]) setparam(str, file_name); else unsetparam(str); } show_edit_form(lbs, atoi(getparam("edit_id")), FALSE, TRUE, TRUE, FALSE); return; } } if (strieq(command, loc("Edit"))) { if (message_id) { show_edit_form(lbs, message_id, FALSE, TRUE, FALSE, FALSE); return; } } if (strieq(command, loc("Reply"))) { show_edit_form(lbs, message_id, TRUE, FALSE, FALSE, FALSE); return; } if (strieq(command, loc("Update"))) { show_edit_form(lbs, atoi(getparam("edit_id")), FALSE, TRUE, FALSE, TRUE); return; } if (strieq(command, loc("Submit")) || strieq(command, "Submit")) { if (isparam("mirror_id")) submit_elog_mirror(lbs); else submit_elog(lbs); return; } if (strieq(command, loc("Find"))) { /* stip message id */ if (dec_path[0]) { sprintf(str, "../%s/?cmd=%s", lbs->name_enc, loc("Find")); redirect(lbs, str); return; } show_find_form(lbs); return; } if (strieq(command, loc("Search"))) { if (dec_path[0] && atoi(dec_path) == 0 && strchr(dec_path, '/') != NULL) { sprintf(str, "Invalid URL: %s", dec_path); show_error(str); return; } show_elog_list(lbs, 0, 0, 1, NULL); return; } if (strieq(command, loc("Last day"))) { redirect(lbs, "past1"); return; } if (strieq(command, loc("Last 10"))) { redirect(lbs, "last10"); return; } if (strieq(command, loc("Copy to"))) { copy_to(lbs, message_id, getparam("destc"), 0, 0); return; } if (strieq(command, loc("Move to"))) { copy_to(lbs, message_id, getparam("destm"), 1, 0); return; } if (strieq(command, loc("Admin")) || strieq(command, loc("Change elogd.cfg"))) { show_admin_page(lbs, NULL); return; } sprintf(str, loc("Change %s"), "[global]"); if (strieq(command, str)) { show_admin_page(lbs, "global"); return; } sprintf(str2, "[global %s]", lbs->top_group); sprintf(str, loc("Change %s"), str2); if (strieq(command, str)) { show_admin_page(lbs, lbs->top_group); return; } if (strieq(command, loc("Change password")) || (isparam("newpwd") && !strieq(command, loc("Cancel")) && !strieq(command, loc("Save")))) { show_change_pwd_page(lbs); return; } if (strieq(command, loc("Save"))) { if (isparam("config")) { if (!strieq(getparam("config"), getparam("new_user_name"))) { if (get_user_line (lbs->name, getparam("new_user_name"), NULL, NULL, NULL, NULL) == 1) { sprintf(str, "%s \"%s\" %s", loc("Login name"), getparam("new_user_name"), loc("exists already")); show_error(str); return; } } /* change existing user */ if (!save_user_config(lbs, getparam("config"), FALSE, FALSE)) return; } else if (isparam("new_user_name")) { /* new user */ if (!save_user_config(lbs, getparam("new_user_name"), TRUE, FALSE)) return; } else { if (isparam("global")) { if (strieq(getparam("global"), "global")) strcpy(section, "global"); else sprintf(section, "global %s", getparam("global")); } else strlcpy(section, lbs->name, sizeof(section)); if (!save_admin_config(section, _mtext, str)) { /* save cfg file */ show_error(str); return; } } if (lbs) sprintf(str, "../%s/", lbs->name_enc); else sprintf(str, "."); if (isparam("new_user_name")) sprintf(str + strlen(str), "?cmd=%s&cfg_user=%s", loc("Config"), getparam("new_user_name")); else if (isparam("cfg_user")) sprintf(str + strlen(str), "?cmd=%s&cfg_user=%s", loc("Config"), getparam("cfg_user")); else if (getcfg(lbs->name, "password file", str2)) sprintf(str + strlen(str), "?cmd=%s", loc("Config")); redirect(lbs, str); return; } if (strieq(command, "Activate")) { if (!save_user_config(lbs, getparam("new_user_name"), TRUE, TRUE)) return; setparam("cfg_user", getparam("new_user_name")); show_config_page(lbs); return; } if (strieq(command, loc("Remove user"))) { remove_user(lbs, getparam("config")); /* if removed user is current user, do logout */ if (strieq(getparam("config"), getparam("unm"))) { /* log activity */ logf(lbs, "LOGOUT"); /* set cookies */ set_login_cookies(lbs, "", ""); } /* continue configuration as administrator */ unsetparam("cfg_user"); show_config_page(lbs); return; } if (strieq(command, loc("New user"))) { show_new_user_page(lbs); return; } if (strieq(command, loc("Forgot"))) { show_forgot_pwd_page(lbs); return; } if (strieq(command, loc("Config"))) { if (!getcfg(lbs->name, "Password file", str)) show_admin_page(lbs, NULL); else show_config_page(lbs); return; } if (strieq(command, loc("Download")) || strieq(command, "Download")) { show_download_page(lbs, dec_path); return; } if (strieq(command, loc("CSV Import"))) { show_import_page(lbs); return; } if (strieq(command, "getmd5")) { show_md5_page(lbs); return; } if (strieq(command, loc("Synchronize"))) { synchronize(lbs, FALSE); return; } if (strieq(command, loc("Logout"))) { /* log activity */ logf(lbs, "LOGOUT"); if (getcfg(lbs->name, "Logout to main", str) && atoi(str) == 1) { sprintf(str, "../"); setparam("redir", str); } set_login_cookies(lbs, "", ""); return; } if (strieq(command, loc("Delete"))) { show_elog_delete(lbs, message_id); return; } /* check for welcome page */ if (!_cmdline[0] && getcfg(lbs->name, "Welcome page", str) && str[0]) { /* check if file starts with an absolute directory */ if (str[0] == DIR_SEPARATOR || str[1] == ':') strcpy(file_name, str); else { strlcpy(file_name, resource_dir, sizeof(file_name)); strlcat(file_name, str, sizeof(file_name)); } send_file_direct(file_name); return; } /* check for start page */ if (!_cmdline[0] && getcfg(lbs->name, "Start page", str) && str[0]) { redirect(lbs, str); return; } /* check for calender */ if (strieq(dec_path, "cal.html")) { show_calendar(lbs); return; } /* show page listing or display single entry */ if (dec_path[0] == 0) show_elog_list(lbs, 0, 0, 1, NULL); else show_elog_message(lbs, dec_path, command); return; } /*------------------------------------------------------------------*/ void decode_get(char *logbook, char *string) { char path[256]; char *p, *pitem; setparam("cmdline", string); strlcpy(path, string, sizeof(path)); path[255] = 0; if (strchr(path, '?')) *strchr(path, '?') = 0; setparam("path", path); if (strchr(string, '?')) { p = strchr(string, '?') + 1; /* cut trailing "/" from netscape */ if (p[strlen(p) - 1] == '/') p[strlen(p) - 1] = 0; p = strtok(p, "&"); while (p != NULL) { pitem = p; p = strchr(p, '='); if (p != NULL) { *p++ = 0; url_decode(pitem); url_decode(p); if (!setparam(pitem, p)) return; p = strtok(NULL, "&"); } } } interprete(logbook, path); } /*------------------------------------------------------------------*/ void decode_post(LOGBOOK * lbs, char *string, char *boundary, int length) { int n_att; char *pinit, *p, *ptmp, file_name[256], full_name[256], str[NAME_LENGTH], line[NAME_LENGTH], item[NAME_LENGTH]; n_att = 0; pinit = string; /* return if no boundary defined */ if (!boundary[0]) return; if (strstr(string, boundary)) string = strstr(string, boundary) + strlen(boundary); do { if (strstr(string, "name=")) { strlcpy(line, strstr(string, "name=") + 5, sizeof(line)); if (strchr(line, '\r')) *strchr(line, '\r') = 0; if (strchr(line, '\n')) *strchr(line, '\n') = 0; strcpy(item, line); if (item[0] == '\"') { strcpy(item, line + 1); if (strchr(item, '\"')) *strchr(item, '\"') = 0; } else if (strchr(item, ' ')) *strchr(item, ' ') = 0; if (strncmp(item, "attachment", 10) == 0) { /* attachment names from previous uploads */ n_att = atoi(item + 10) + 1; } if (strncmp(item, "csvfile", 7) == 0) { /* evaluate CSV import file */ if (strstr(string, "filename=")) { p = strstr(string, "filename=") + 9; if (*p == '\"') p++; if (strstr(p, "\r\n\r\n")) string = strstr(p, "\r\n\r\n") + 4; else if (strstr(p, "\r\r\n\r\r\n")) string = strstr(p, "\r\r\n\r\r\n") + 6; if (strchr(p, '\"')) *strchr(p, '\"') = 0; /* set attachment filename */ strcpy(file_name, p); if (file_name[0]) { if (verbose) printf("decode_post: Found CSV import file\n"); } /* find next boundary */ ptmp = string; do { while (*ptmp != '-') ptmp++; if ((p = strstr(ptmp, boundary)) != NULL) { if (*(p - 1) == '-') p--; while (*p == '-') p--; if (*p == 10) p--; if (*p == 13) p--; p++; break; } else ptmp += strlen(ptmp); } while (TRUE); /* import CSVfile */ if (file_name[0]) { setparam("csvfile", file_name); csv_import(lbs, string, file_name); return; } string = strstr(p, boundary) + strlen(boundary); } else string = strstr(string, boundary) + strlen(boundary); } else if (strncmp(item, "attfile", 7) == 0) { /* evaluate file attachment */ if (strstr(string, "filename=")) { p = strstr(string, "filename=") + 9; if (*p == '\"') p++; if (strstr(p, "\r\n\r\n")) string = strstr(p, "\r\n\r\n") + 4; else if (strstr(p, "\r\r\n\r\r\n")) string = strstr(p, "\r\r\n\r\r\n") + 6; if (strchr(p, '\"')) *strchr(p, '\"') = 0; /* set attachment filename */ strcpy(file_name, p); if (file_name[0]) { if (verbose) printf("decode_post: Found attachment %s\n", file_name); /* check filename for invalid characters */ if (strpbrk(file_name, ",;")) { sprintf(str, "Error: Filename \"%s\" contains invalid character", file_name); show_error(str); return; } } /* find next boundary */ ptmp = string; do { while (*ptmp != '-') ptmp++; if ((p = strstr(ptmp, boundary)) != NULL) { if (*(p - 1) == '-') p--; while (*p == '-') p--; if (*p == 10) p--; if (*p == 13) p--; p++; break; } else ptmp += strlen(ptmp); } while (TRUE); /* save attachment */ if (file_name[0]) { el_submit_attachment(lbs, file_name, string, (int) (p - string), full_name); sprintf(str, "attachment%d", n_att++); setparam(str, full_name); } string = strstr(p, boundary) + strlen(boundary); } else string = strstr(string, boundary) + strlen(boundary); } else { p = string; if (strstr(p, "\r\n\r\n")) p = strstr(p, "\r\n\r\n") + 4; else if (strstr(p, "\r\r\n\r\r\n")) p = strstr(p, "\r\r\n\r\r\n") + 6; if (strstr(p, boundary)) { string = strstr(p, boundary) + strlen(boundary); *strstr(p, boundary) = 0; ptmp = p + (strlen(p) - 1); while (*ptmp == '-') *ptmp-- = 0; while (*ptmp == '\n' || *ptmp == '\r') *ptmp-- = 0; } if (setparam(item, p) == 0) return; } while (*string == '-' || *string == '\n' || *string == '\r') string++; } } while ((int) (string - pinit) < length); interprete(lbs->name, ""); } /*------------------------------------------------------------------*/ BOOL cron_match(char *str, int value, BOOL ignore_star) { int low, high; if (atoi(str) == value) return TRUE; if (!ignore_star && str[0] == '*') return TRUE; /* check range */ if (strchr(str, '-')) { low = atoi(str); high = atoi(strchr(str, '-') + 1); return value >= low && value <= high; } return FALSE; } void check_cron() /* check 'mirror cron' etnry in configuration file minute (0-59) hour (0-23) day of month (1-31) month of year (1-12) day of week (0-6, 0 is Sunday) Each of these patterns might be an asterisk (meaning all legal values) or a list of elements separated by commas. */ { int i, j, n; BOOL min_flag, hour_flag, day_flag, mon_flag, wday_flag; time_t now; char *p, str[256], cron[5][256]; struct tm *ts; static struct tm last_time; char list[60][NAME_LENGTH]; if (!getcfg("global", "mirror cron", str)) return; for (i = 0; i < 5; i++) strcpy(cron[i], "*"); i = 0; p = strtok(str, " "); while (p) { strcpy(cron[i++], p); p = strtok(NULL, " "); } time(&now); ts = localtime(&now); /* check once every minute */ if (last_time.tm_year && last_time.tm_min != ts->tm_min) { min_flag = hour_flag = day_flag = mon_flag = wday_flag = FALSE; for (i = 0; i < 5; i++) { n = strbreak(cron[i], list, 60, ","); for (j = 0; j < n; j++) { /* minutes */ if (i == 0 && cron_match(list[j], ts->tm_min, FALSE)) min_flag = TRUE; /* hours */ if (i == 1 && cron_match(list[j], ts->tm_hour, FALSE)) hour_flag = TRUE; /* day of month */ if (i == 2 && cron_match(list[j], ts->tm_mday, FALSE)) day_flag = TRUE; /* month of year */ if (i == 3 && cron_match(list[j], ts->tm_mon, FALSE)) mon_flag = TRUE; /* weekday */ if (i == 4 && cron_match(list[j], ts->tm_wday, TRUE)) wday_flag = TRUE; } } if (min_flag && hour_flag && ((day_flag && mon_flag) || wday_flag)) { rem_host[0] = 0; logf(NULL, "Cron job started"); /* synchronize all logbooks */ setcfg_topgroup(""); synchronize(NULL, TRUE); } } memcpy(&last_time, ts, sizeof(struct tm)); } /*------------------------------------------------------------------*/ BOOL _abort = FALSE; BOOL _hup = FALSE; void ctrlc_handler(int sig) { if (sig) _abort = TRUE; } void hup_handler(int sig) { if (sig) _hup = TRUE; } /*------------------------------------------------------------------*/ #define N_MAX_CONNECTION 10 #define KEEP_ALIVE_TIME 60 int ka_sock[N_MAX_CONNECTION]; int ka_time[N_MAX_CONNECTION]; struct in_addr remote_addr[N_MAX_CONNECTION]; char remote_host[N_MAX_CONNECTION][256]; void server_loop(int tcp_port, int daemon) { int status, i, n, n_error, authorized, min, i_min, i_conn, length; struct sockaddr_in serv_addr, acc_addr; char pwd[256], str[256], url[256], cl_pwd[256], *p, *pd; char cookie[256], boundary[256], list[1000], theme[256], host_list[MAX_N_LIST][NAME_LENGTH], rem_host_ip[256], logbook[256], logbook_enc[256]; int lsock, len, flag, content_length, header_length; struct hostent *phe; fd_set readfds; struct timeval timeout; char *net_buffer = NULL; int net_buffer_size; i_conn = content_length = 0; net_buffer_size = 100000; net_buffer = malloc(net_buffer_size); return_buffer_size = 100000; return_buffer = malloc(return_buffer_size); #ifdef OS_WINNT { WSADATA WSAData; /* Start windows sockets */ if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0) return; } #endif /* create a new socket */ lsock = socket(AF_INET, SOCK_STREAM, 0); if (lsock == -1) { printf("Cannot create socket\n"); return; } /* bind local node name and port to socket */ memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; /* if no hostname given with the -h flag, listen on any interface */ if (tcp_hostname[0] == 0) serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); else { /* look up the given hostname. gethostbyname() will take a hostname or an IP address */ phe = gethostbyname(tcp_hostname); if (!phe) { printf("Cannot find address for -h %s\n", tcp_hostname); return; } if (phe->h_addrtype != AF_INET) { printf("Non Internet address for -h %s\n", tcp_hostname); return; } memcpy(&serv_addr.sin_addr.s_addr, phe->h_addr_list[0], phe->h_length); } serv_addr.sin_port = htons((short) tcp_port); /* try reusing address */ flag = 1; setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(INT)); status = bind(lsock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (status < 0) { printf ("Cannot bind to port %d.\nPlease try later or use the \"-p\" flag to specify a different port\n", tcp_port); return; } /* get host name for mail notification */ gethostname(host_name, sizeof(host_name)); phe = gethostbyname(host_name); if (phe != NULL) phe = gethostbyaddr(phe->h_addr, sizeof(int), AF_INET); /* if domain name is not in host name, hope to get it from phe */ if (strchr(host_name, '.') == NULL && phe != NULL) strcpy(host_name, phe->h_name); /* open configuration file */ getcfg("dummy", "dummy", str); /* initiate daemon */ if (daemon) { printf("Becoming a daemon...\n"); ss_daemon_init(); } #ifdef OS_UNIX /* create PID file if given as command line parameter or if running under root */ if (geteuid() == 0 || pidfile[0]) { int fd; char buf[20]; struct stat finfo; if (pidfile[0] == 0) strcpy(pidfile, PIDFILE); /* check if file exists */ if (stat(pidfile, &finfo) >= 0) { printf("File \"%s\" exists, using \"%s.%d\" instead.\n", pidfile, pidfile, tcp_port); sprintf(pidfile + strlen(pidfile), ".%d", tcp_port); /* check again for the new name */ if (stat(pidfile, &finfo) >= 0) { /* never overwrite a file */ printf("Refuse to overwrite existing file \"%s\".\n", pidfile); exit(EXIT_FAILURE); } } fd = open(pidfile, O_CREAT | O_RDWR, 0644); if (fd < 0) { sprintf(str, "Error creating pid file \"%s\"", pidfile); perror(str); exit(EXIT_FAILURE); } sprintf(buf, "%d\n", (int) getpid()); if (write(fd, buf, strlen(buf)) == -1) { sprintf(str, "Error writing to pid file \"%s\"", pidfile); perror(str); exit(EXIT_FAILURE); } close(fd); } /* install signal handler */ signal(SIGTERM, ctrlc_handler); signal(SIGINT, ctrlc_handler); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, hup_handler); /* give up root privilege */ if (geteuid() == 0) { if (!getcfg("global", "Grp", str) || setgroup(str) < 0) { printf("Falling back to default group \"elog\"\n"); if (setgroup("elog") < 0) { printf("Falling back to default group \"%s\"\n", DEFAULT_GROUP); if (setgroup(DEFAULT_GROUP) < 0) { printf("Refuse to run as setgid root.\n"); printf ("Please consider to define a Grp statement in configuration file\n"); exit(EXIT_FAILURE); } } } if (!getcfg("global", "Usr", str) || setuser(str) < 0) { printf("Falling back to default user \"elog\"\n"); if (setuser("elog") < 0) { printf("Falling back to default user \"%s\"\n", DEFAULT_USER); if (setuser(DEFAULT_USER) < 0) { printf("Refuse to run as setuid root.\n"); printf ("Please consider to define a Usr statement in configuration file\n"); exit(EXIT_FAILURE); } } } } #endif /* load initial configuration */ check_config(); /* build logbook indices */ if (el_index_logbooks(FALSE) != EL_SUCCESS) exit(EXIT_FAILURE); /* listen for connection */ status = listen(lsock, SOMAXCONN); if (status < 0) { printf("Cannot listen\n"); return; } printf("Server listening on port %d...\n", tcp_port); do { FD_ZERO(&readfds); FD_SET(lsock, &readfds); for (i = 0; i < N_MAX_CONNECTION; i++) if (ka_sock[i] > 0) FD_SET(ka_sock[i], &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; status = select(FD_SETSIZE, (void *) &readfds, NULL, NULL, (void *) &timeout); /* check UNIX signal flags */ if (_abort) break; if (FD_ISSET(lsock, &readfds)) { len = sizeof(acc_addr); _sock = accept(lsock, (struct sockaddr *) &acc_addr, &len); /* find new entry in socket table */ for (i = 0; i < N_MAX_CONNECTION; i++) if (ka_sock[i] == 0) break; /* recycle last connection */ if (i == N_MAX_CONNECTION) { for (i = i_min = 0, min = ka_time[0]; i < N_MAX_CONNECTION; i++) if (ka_time[i] < min) { min = ka_time[i]; i_min = i; } closesocket(ka_sock[i_min]); ka_sock[i_min] = 0; i = i_min; #ifdef DEBUG_CONN printf("## close connection %d\n", i_min); #endif } i_conn = i; ka_sock[i_conn] = _sock; ka_time[i_conn] = (int) time(NULL); /* save remote host address */ memcpy(&remote_addr[i_conn], &(acc_addr.sin_addr), sizeof(rem_addr)); memcpy(&rem_addr, &(acc_addr.sin_addr), sizeof(rem_addr)); phe = gethostbyaddr((char *) &rem_addr, 4, PF_INET); if (phe != NULL) strcpy(remote_host[i_conn], phe->h_name); else strcpy(remote_host[i_conn], (char *) inet_ntoa(rem_addr)); strcpy(rem_host, remote_host[i_conn]); #ifdef DEBUG_CONN printf("## open new connection %d\n", i_conn); #endif } else { /* check if open connection received data */ for (i = 0; i < N_MAX_CONNECTION; i++) if (ka_sock[i] > 0 && FD_ISSET(ka_sock[i], &readfds)) break; if (i == N_MAX_CONNECTION) { _sock = 0; } else { i_conn = i; _sock = ka_sock[i_conn]; ka_time[i_conn] = (int) time(NULL); memcpy(&rem_addr, &remote_addr[i_conn], sizeof(rem_addr)); strcpy(rem_host, remote_host[i_conn]); #ifdef DEBUG_CONN printf("## received request on connection %d\n", i_conn); #endif } } /* turn off keep_alive by default */ keep_alive = FALSE; if (_sock > 0) { memset(net_buffer, 0, net_buffer_size); len = 0; header_length = 0; n_error = 0; do { FD_ZERO(&readfds); FD_SET(_sock, &readfds); timeout.tv_sec = 6; timeout.tv_usec = 0; status = select(FD_SETSIZE, (void *) &readfds, NULL, NULL, (void *) &timeout); if (FD_ISSET(_sock, &readfds)) i = recv(_sock, net_buffer + len, net_buffer_size - len, 0); else goto finished; /* abort if connection got broken */ if (i < 0) goto finished; if (i > 0) len += i; /* check if net_buffer needs to be increased */ if (len == net_buffer_size) { net_buffer = realloc(net_buffer, net_buffer_size + 100000); if (net_buffer == NULL) { sprintf(str, "Error: Cannot increase net_buffer, out of memory, net_buffer_size = %d", net_buffer_size); show_error(str); send(_sock, return_buffer, strlen_retbuf + 1, 0); keep_alive = 0; if (verbose) { printf("==== Return ================================\n"); puts(return_buffer); printf("\n\n"); } goto finished; } memset(net_buffer + net_buffer_size, 0, 100000); net_buffer_size += 100000; } if (i == 0) { n_error++; if (n_error == 100) goto finished; } /* finish when empty line received */ if (strstr(net_buffer, "GET") != NULL && strstr(net_buffer, "POST") == NULL) { if (len > 4 && strcmp(&net_buffer[len - 4], "\r\n\r\n") == 0) break; if (len > 6 && strcmp(&net_buffer[len - 6], "\r\r\n\r\r\n") == 0) break; } else if (strstr(net_buffer, "POST") != NULL) { if (header_length == 0) { /* extract logbook */ strlcpy(str, net_buffer + 6, sizeof(str)); if (strstr(str, "HTTP")) *(strstr(str, "HTTP") - 1) = 0; strlcpy(logbook, str, sizeof(logbook)); strlcpy(logbook_enc, str, sizeof(logbook)); url_decode(logbook); /* extract header and content length */ if (strstr(net_buffer, "Content-Length:")) content_length = atoi(strstr(net_buffer, "Content-Length:") + 15); else if (strstr(net_buffer, "Content-length:")) content_length = atoi(strstr(net_buffer, "Content-length:") + 15); boundary[0] = 0; if (strstr(net_buffer, "boundary=")) { strlcpy(boundary, strstr(net_buffer, "boundary=") + 9, sizeof(boundary)); if (strchr(boundary, '\r')) *strchr(boundary, '\r') = 0; } if (strstr(net_buffer, "\r\n\r\n")) header_length = (INT) strstr(net_buffer, "\r\n\r\n") - (INT) net_buffer + 4; if (strstr(net_buffer, "\r\r\n\r\r\n")) header_length = (INT) strstr(net_buffer, "\r\r\n\r\r\n") - (INT) net_buffer + 6; if (header_length) net_buffer[header_length - 1] = 0; } if (header_length > 0 && len >= header_length + content_length) break; } else if (strstr(net_buffer, "HEAD") != NULL) { /* just return header */ rsprintf("HTTP/1.1 200 OK\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); rsprintf("Connection: close\r\n"); rsprintf("Content-Type: text/html\r\n\r\n"); keep_alive = FALSE; return_length = strlen_retbuf + 1; send(_sock, return_buffer, return_length, 0); goto finished; } else if (strstr(net_buffer, "OPTIONS") != NULL) goto finished; else { puts(net_buffer); goto finished; } } while (1); if (!strchr(net_buffer, '\r')) goto finished; if (verbose) { puts("\n"); puts(net_buffer); } /* initialize parametr array */ initparam(); /* extract cookies */ if ((p = strstr(net_buffer, "Cookie:")) != NULL) { p += 6; do { p++; while (*p && *p == ' ') p++; strlcpy(str, p, sizeof(str)); for (i = 0; i < (int) strlen(str); i++) if (str[i] == '=' || str[i] == ';') break; if (str[i] == '=') { str[i] = 0; p += i + 1; for (i = 0; *p && *p != ';' && *p != '\r' && *p != '\n'; i++) cookie[i] = *p++; cookie[i] = 0; } else { /* empty cookie */ str[i] = 0; cookie[0] = 0; p += i; } /* store cookie as parameter */ setparam(str, cookie); } while (*p && *p == ';'); } /* extract referer */ referer[0] = 0; if ((p = strstr(net_buffer, "Referer:")) != NULL) { p += 9; while (*p && *p == ' ') p++; strlcpy(referer, p, sizeof(referer)); if (strchr(referer, '\r')) *strchr(referer, '\r') = 0; if (strchr(referer, '?')) *strchr(referer, '?') = 0; for (p = referer + strlen(referer) - 1; p > referer && *p != '/'; p--) *p = 0; if (strchr(referer, ' ')) url_encode(referer, sizeof(referer)); } /* extract browser */ browser[0] = 0; if ((p = strstr(net_buffer, "User-Agent:")) != NULL) { p += 11; while (*p && *p == ' ') p++; strlcpy(browser, p, sizeof(browser)); if (strchr(browser, '\r')) *strchr(browser, '\r') = 0; } /* extract host */ http_host[0] = 0; if ((p = strstr(net_buffer, "Host:")) != NULL) { p += 5; while (*p && *p == ' ') p++; strlcpy(http_host, p, sizeof(http_host)); if (strchr(http_host, '\r')) *strchr(http_host, '\r') = 0; } /* extract "X-Forwarded-For:" */ if ((p = strstr(net_buffer, "X-Forwarded-For:")) != NULL) { p += 16; while (*p && *p == ' ') p++; strlcpy(str, p, sizeof(str)); if (strchr(str, '\r')) *strchr(str, '\r') = 0; #ifdef _MSC_VER rem_addr.S_un.S_addr = inet_addr(str); #else rem_addr.s_addr = inet_addr(str); #endif phe = gethostbyaddr((char *) &rem_addr, 4, PF_INET); if (phe != NULL) { strcpy(remote_host[i_conn], phe->h_name); strcpy(rem_host, remote_host[i_conn]); } } memset(return_buffer, 0, return_buffer_size); strlen_retbuf = 0; if (strncmp(net_buffer, "GET", 3) != 0 && strncmp(net_buffer, "POST", 4) != 0) goto finished; return_length = 0; /* extract logbook */ if (strchr(net_buffer, '/') == NULL || strchr(net_buffer, '\r') == NULL || strstr(net_buffer, "HTTP") == NULL) { /* invalid request, make valid */ strcpy(net_buffer, "GET / HTTP/1.0\r\n\r\n"); } /* initialize topgroups */ setcfg_topgroup(""); p = strchr(net_buffer, '/') + 1; logbook[0] = 0; for (i = 0; *p && *p != '/' && *p != '?' && *p != ' '; i++) logbook[i] = *p++; logbook[i] = 0; strcpy(logbook_enc, logbook); url_decode(logbook); /* check for trailing '/' after logbook */ if (strstr(net_buffer, "POST") == NULL) { // fix for konqueror if (logbook[0] && *p == ' ') { if (!strstr(logbook, ".css") && !strstr(logbook, ".htm") && !strstr(logbook, ".gif") && !strstr(logbook, ".jpg") && !strstr(logbook, ".png")) { sprintf(str, "%s/", logbook_enc); redirect(NULL, str); goto redir; } } } /* check for trailing '/' after logbook/ID */ if (logbook[0] && *p == '/' && *(p + 1) != ' ') { sprintf(url, "%s", logbook_enc); pd = url + strlen(url); while (*p && *p != ' ') *pd++ = *p++; *pd = 0; if (*(p - 1) == '/') { sprintf(str, "Invalid URL: %s", url); show_error(str); send(_sock, return_buffer, strlen_retbuf + 1, 0); keep_alive = 0; if (verbose) { printf("==== Return ================================\n"); puts(return_buffer); printf("\n\n"); } goto finished; } } /* check if logbook exists */ for (i = 0;; i++) { if (!enumgrp(i, str)) break; if (strieq(logbook, str)) break; } if (strstr(logbook, ".gif") || strstr(logbook, ".jpg") || strstr(logbook, ".jpg") || strstr(logbook, ".png") || strstr(logbook, ".ico") || strstr(logbook, ".htm") || strstr(logbook, ".css")) { /* check if file in resource directory */ strlcpy(str, resource_dir, sizeof(str)); strlcat(str, logbook, sizeof(str)); if (exist_file(str)) send_file_direct(str); else { /* else search file in themes directory */ strlcpy(str, resource_dir, sizeof(str)); strlcat(str, "themes", sizeof(str)); strlcat(str, DIR_SEPARATOR_STR, sizeof(str)); if (getcfg("global", "theme", theme)) strlcat(str, theme, sizeof(str)); else strlcat(str, "default", sizeof(str)); strlcat(str, DIR_SEPARATOR_STR, sizeof(str)); strlcat(str, logbook, sizeof(str)); send_file_direct(str); } send(_sock, return_buffer, return_length, 0); if (verbose) { printf("==== Return ================================\n"); puts(return_buffer); printf("\n\n"); } goto finished; } else { if (!strieq(logbook, str) && logbook[0]) { /* check for top group */ sprintf(str, "Top group %s", logbook); if (!getcfg("global", str, list)) { sprintf(str, "Error: logbook \"%s\" not defined in elogd.cfg", logbook); show_error(str); send(_sock, return_buffer, strlen(return_buffer), 0); if (verbose) { printf("==== Return ================================\n"); puts(return_buffer); printf("\n\n"); } goto finished; } } } /* if no logbook is given and only one logbook defined, use this one */ if (!logbook[0]) { for (i = n = 0;; i++) { if (!enumgrp(i, str)) break; if (is_logbook(str)) n++; } if (n == 1) { strlcpy(logbook, str, sizeof(logbook)); strlcpy(logbook_enc, logbook, sizeof(logbook_enc)); url_encode(logbook_enc, sizeof(logbook_enc)); strlcat(logbook_enc, "/", sizeof(logbook_enc)); /* redirect to logbook, necessary to get optional cookies for that logbook */ redirect(NULL, logbook_enc); send(_sock, return_buffer, strlen(return_buffer), 0); if (verbose) { printf("==== Return ================================\n"); puts(return_buffer); printf("\n\n"); } goto finished; } } /*---- check "hosts deny" ----*/ authorized = 1; if (getcfg(logbook, "Hosts deny", list)) { strcpy(rem_host_ip, (char *) inet_ntoa(rem_addr)); n = strbreak(list, host_list, MAX_N_LIST, ","); /* check if current connection matches anyone on the list */ for (i = 0; i < n; i++) { if (strieq(rem_host, host_list[i]) || strieq(rem_host_ip, host_list[i]) || strieq(host_list[i], "all")) { if (verbose) printf ("Remote host \"%s\" matches \"%s\" in \"Hosts deny\". Access denied.\n", strieq(rem_host_ip, host_list[i]) ? rem_host_ip : rem_host, host_list[i]); authorized = 0; break; } if (host_list[i][0] == '.') { if (strlen(rem_host) > strlen(host_list[i]) && strieq(host_list[i], rem_host + strlen(rem_host) - strlen(host_list[i]))) { if (verbose) printf ("Remote host \"%s\" matches \"%s\" in \"Hosts deny\". Access denied.\n", rem_host, host_list[i]); authorized = 0; break; } } if (host_list[i][strlen(host_list[i]) - 1] == '.') { strcpy(str, rem_host_ip); if (strlen(str) > strlen(host_list[i])) str[strlen(host_list[i])] = 0; if (strieq(host_list[i], str)) { if (verbose) printf ("Remote host \"%s\" matches \"%s\" in \"Hosts deny\". Access denied.\n", rem_host_ip, host_list[i]); authorized = 0; break; } } } } /*---- check "hosts allow" ----*/ if (getcfg(logbook, "Hosts allow", list)) { strcpy(rem_host_ip, (char *) inet_ntoa(acc_addr.sin_addr)); n = strbreak(list, host_list, MAX_N_LIST, ","); /* check if current connection matches anyone on the list */ for (i = 0; i < n; i++) { if (strieq(rem_host, host_list[i]) || strieq(rem_host_ip, host_list[i]) || strieq(host_list[i], "all")) { if (verbose) printf ("Remote host \"%s\" matches \"%s\" in \"Hosts allow\". Access granted.\n", strieq(rem_host_ip, host_list[i]) ? rem_host_ip : rem_host, host_list[i]); authorized = 1; break; } if (host_list[i][0] == '.') { if (strlen(rem_host) > strlen(host_list[i]) && strieq(host_list[i], rem_host + strlen(rem_host) - strlen(host_list[i]))) { if (verbose) printf ("Remote host \"%s\" matches \"%s\" in \"Hosts allow\". Access granted.\n", rem_host, host_list[i]); authorized = 1; break; } } if (host_list[i][strlen(host_list[i]) - 1] == '.') { strcpy(str, rem_host_ip); if (strlen(str) > strlen(host_list[i])) str[strlen(host_list[i])] = 0; if (strieq(host_list[i], str)) { if (verbose) printf ("Remote host \"%s\" matches \"%s\" in \"Hosts allow\". Access granted.\n", rem_host_ip, host_list[i]); authorized = 1; break; } } } } if (!authorized) { keep_alive = 0; goto finished; } /* ask for password if configured */ authorized = 1; if (getcfg(logbook, "Read Password", pwd)) { authorized = 0; /* decode authorization */ if (strstr(net_buffer, "Authorization:")) { p = strstr(net_buffer, "Authorization:") + 14; if (strstr(p, "Basic")) { p = strstr(p, "Basic") + 6; while (*p == ' ') p++; i = 0; while (*p && *p != ' ' && *p != '\r') str[i++] = *p++; str[i] = 0; } base64_decode(str, cl_pwd); if (strchr(cl_pwd, ':')) { p = strchr(cl_pwd, ':') + 1; do_crypt(p, str); strcpy(cl_pwd, str); /* check authorization */ if (strcmp(str, pwd) == 0) authorized = 1; } } } /* check for Keep-alive */ if (strstr(net_buffer, "Keep-Alive") != NULL && use_keepalive) keep_alive = TRUE; if (!authorized) { /* return request for authorization */ rsprintf("HTTP/1.1 401 Authorization Required\r\n"); rsprintf("Server: ELOG HTTP %s\r\n", VERSION); rsprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", logbook); rsprintf("Connection: close\r\n"); rsprintf("Content-Type: text/html\r\n\r\n"); rsprintf("\r\n"); rsprintf("401 Authorization Required\r\n"); rsprintf("\r\n"); rsprintf("

Authorization Required

\r\n"); rsprintf("This server could not verify that you\r\n"); rsprintf("are authorized to access the document\r\n"); rsprintf("requested. Either you supplied the wrong\r\n"); rsprintf("credentials (e.g., bad password), or your\r\n"); rsprintf("browser doesn't understand how to supply\r\n"); rsprintf("the credentials required.

\r\n"); rsprintf("\r\n"); keep_alive = FALSE; } else { if (strncmp(net_buffer, "GET", 3) == 0) { /* extract path and commands */ *strchr(net_buffer, '\r') = 0; if (!strstr(net_buffer, "HTTP")) goto finished; *(strstr(net_buffer, "HTTP") - 1) = 0; /* strip logbook from path */ p = net_buffer + 5; for (i = 0; *p && *p != '/' && *p != '?'; p++); while (*p && *p == '/') p++; /* decode command and return answer */ decode_get(logbook, p); } else if (strncmp(net_buffer, "POST", 4) == 0) { if (verbose) puts(net_buffer + header_length); /* get logbook from list (needed for attachment dir) */ for (i = 0; lb_list[i].name[0]; i++) if (strieq(logbook, lb_list[i].name)) break; decode_post(&lb_list[i], net_buffer + header_length, boundary, content_length); } else { net_buffer[50] = 0; sprintf(str, "Unknown request:

%s", net_buffer); show_error(str); } } redir: if (return_length != -1) { if (return_length == 0) return_length = strlen_retbuf; if ((keep_alive && strstr(return_buffer, "Content-Length") == NULL) || strstr(return_buffer, "Content-Length") > strstr(return_buffer, "\r\n\r\n")) { /*---- add content-length ----*/ p = strstr(return_buffer, "\r\n\r\n"); if (p != NULL) { length = strlen(p + 4); header_length = (int) (p - return_buffer); memcpy(header_buffer, return_buffer, header_length); sprintf(header_buffer + header_length, "\r\nContent-Length: %d\r\n\r\n", length); send(_sock, header_buffer, strlen(header_buffer), 0); send(_sock, p + 4, length, 0); if (verbose) { printf("==== Return ================================\n"); puts(header_buffer); puts(p + 2); printf("\n"); } } else { printf("Internal error, no valid header!\n"); keep_alive = 0; } } else { send(_sock, return_buffer, return_length, 0); if (verbose) { printf("==== Return ================================\n"); puts(return_buffer); printf("\n\n"); } } finished: if (!keep_alive) { closesocket(_sock); ka_sock[i_conn] = 0; #ifdef DEBUG_CONN printf("## close connection %d\n", i_conn); #endif } } } #ifdef OS_WINNT /* under windows, check if configuration changed (via stat()) once each access */ check_config(); #else /* under unix, rely on "kill -HUP elogd" */ if (_hup) { /* reload configuration */ check_config(); _hup = FALSE; } #endif /* check for periodic tasks */ check_cron(); } while (!_abort); printf("Server aborted.\n"); } /*------------------------------------------------------------------*/ void create_password(char *logbook, char *name, char *pwd) { int fh, length, i; char *cfgbuffer, str[256], *p; fh = open(config_file, O_RDONLY); if (fh < 0) { /* create new file */ fh = open(config_file, O_CREAT | O_WRONLY, 0640); if (fh < 0) { printf("Cannot create \"%s\".\n", config_file); return; } sprintf(str, "[%s]\n%s=%s\n", logbook, name, pwd); write(fh, str, strlen(str)); close(fh); printf("File \"%s\" created with password in logbook \"%s\".\n", config_file, logbook); return; } /* read existing file and add password */ length = lseek(fh, 0, SEEK_END); lseek(fh, 0, SEEK_SET); cfgbuffer = malloc(length + 1); if (cfgbuffer == NULL) { close(fh); return; } length = read(fh, cfgbuffer, length); cfgbuffer[length] = 0; close(fh); fh = open(config_file, O_TRUNC | O_WRONLY, 0640); sprintf(str, "[%s]", logbook); /* check if logbook exists already */ if (strstr(cfgbuffer, str)) { p = strstr(cfgbuffer, str); /* search password in current logbook */ do { while (*p && *p != '\n') p++; if (*p && *p == '\n') p++; if (strncmp(p, name, strlen(name)) == 0) { /* replace existing password */ i = (int) (p - cfgbuffer); write(fh, cfgbuffer, i); sprintf(str, "%s=%s\n", name, pwd); write(fh, str, strlen(str)); printf("Password replaced in logbook \"%s\".\n", logbook); while (*p && *p != '\n') p++; if (*p && *p == '\n') p++; /* write remainder of file */ write(fh, p, strlen(p)); free(cfgbuffer); close(fh); return; } } while (*p && *p != '['); if (!*p || *p == '[') { /* enter password into current logbook */ p = strstr(cfgbuffer, str); while (*p && *p != '\n') p++; if (*p && *p == '\n') p++; i = (int) (p - cfgbuffer); write(fh, cfgbuffer, i); sprintf(str, "%s=%s\n", name, pwd); write(fh, str, strlen(str)); printf("Password added to logbook \"%s\".\n", logbook); /* write remainder of file */ write(fh, p, strlen(p)); free(cfgbuffer); close(fh); return; } } else { /* write new logbook entry */ write(fh, cfgbuffer, strlen(cfgbuffer)); sprintf(str, "\n[%s]\n%s=%s\n\n", logbook, name, pwd); write(fh, str, strlen(str)); printf("Password added to new logbook \"%s\".\n", logbook); } free(cfgbuffer); close(fh); } void cleanup(void) { #ifdef OS_UNIX char str[256]; /* regain original uid */ if (setegid(orig_gid) < 0 || seteuid(orig_uid) < 0) printf("Cannot restore original GID/UID.\n"); if (pidfile[0]) { if (remove(pidfile) < 0) { sprintf(str, "Cannot remove pidfile \"%s\"\n", pidfile); perror(str); } } #endif } /*------------------------------------------------------------------*/ int main(int argc, char *argv[]) { int i, fh, tcp_port_cl; int daemon = FALSE; char read_pwd[80], write_pwd[80], admin_pwd[80], str[256], logbook[256]; time_t now; struct tm *tms; printf("elogd %s built %s, %s\n", VERSION, __DATE__, __TIME__); #ifdef OS_UNIX /* save gid/uid to regain later */ orig_gid = getegid(); orig_uid = geteuid(); #endif /* register cleanup function */ atexit(cleanup); tzset(); read_pwd[0] = write_pwd[0] = admin_pwd[0] = logbook[0] = 0; logbook_dir[0] = resource_dir[0] = logbook_dir[0] = pidfile[0] = 0; tcp_port_cl = 0; /* default config file */ strcpy(config_file, "elogd.cfg"); /* evaluate predefined files and directories */ #ifdef CONFIG_FILE strlcpy(config_file, CONFIG_FILE, sizeof(config_file)); #endif #ifdef RESOURCE_DIR strlcpy(resource_dir, RESOURCE_DIR, sizeof(resource_dir)); #endif #ifdef LOGBOOK_DIR strlcpy(logbook_dir, LOGBOOK_DIR, sizeof(logbook_dir)); #endif /* look for config file in command line parameters */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 'c') strcpy(config_file, argv[i + 1]); } /* check for configuration file */ fh = open(config_file, O_RDONLY | O_BINARY); if (fh < 0) { printf("Configuration file \"%s\" not found.\n", config_file); exit(EXIT_FAILURE); } close(fh); /* evaluate directories fron config file */ if (getcfg("global", "Resource Dir", str)) strlcpy(resource_dir, str, sizeof(resource_dir)); if (getcfg("global", "Logbook Dir", str)) strlcpy(logbook_dir, str, sizeof(logbook_dir)); use_keepalive = TRUE; /* parse command line parameters */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 'D') daemon = TRUE; else if (argv[i][0] == '-' && argv[i][1] == 'v') verbose = TRUE; else if (argv[i][0] == '-' && argv[i][1] == 'k') use_keepalive = FALSE; else if (argv[i][0] == '-' && argv[i][1] == 'x') enable_execute = TRUE; else if (argv[i][1] == 't') { time(&now); tms = localtime(&now); printf("Actual date/time: %02d%02d%02d_%02d%02d%02d\n", tms->tm_year % 100, tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec); exit(EXIT_SUCCESS); } else if (argv[i][0] == '-') { if (i + 1 >= argc || argv[i + 1][0] == '-') goto usage; if (argv[i][1] == 'p') tcp_port_cl = atoi(argv[++i]); else if (argv[i][1] == 'c') strcpy(config_file, argv[++i]); else if (argv[i][1] == 's') strcpy(resource_dir, argv[++i]); else if (argv[i][1] == 'd') strcpy(logbook_dir, argv[++i]); else if (argv[i][1] == 'r') strcpy(read_pwd, argv[++i]); else if (argv[i][1] == 'w') strcpy(write_pwd, argv[++i]); else if (argv[i][1] == 'a') strcpy(admin_pwd, argv[++i]); else if (argv[i][1] == 'l') strcpy(logbook, argv[++i]); else if (argv[i][1] == 'h') strlcpy(tcp_hostname, argv[++i], sizeof(tcp_hostname)); else if (argv[i][1] == 'f') strlcpy(pidfile, argv[++i], sizeof(pidfile)); else { usage: printf ("usage: %s [-p port] [-h hostname] [-D] [-c file] [-r pwd] [-w pwd] [-a pwd] [-l logbook] [-k] [-f file]\n\n", argv[0]); printf(" -p TCP/IP port\n"); printf(" -h TCP/IP hostname\n"); printf(" -D become a daemon\n"); printf(" -c specify configuration file\n"); printf(" -s

specify resource directory (themes, icons, ...)\n"); printf(" -d specify logbook root directory\n"); printf(" -v debugging output\n"); printf(" -r create/overwrite read password in config file\n"); printf(" -w create/overwrite write password in config file\n"); printf(" -a create/overwrite admin password in config file\n"); printf(" -l specify logbook for -r and -w commands\n\n"); printf(" -k do not use keep-alive\n"); printf(" -f path/filename for PID file\n"); printf(" -x enable execution of shell commands\n\n"); exit(EXIT_SUCCESS); } } } if ((read_pwd[0] || write_pwd[0] || admin_pwd[0]) && !logbook[0]) { printf("Must specify a lookbook via the -l parameter.\n"); exit(EXIT_SUCCESS); } if (read_pwd[0]) { do_crypt(read_pwd, str); create_password(logbook, "Read Password", str); exit(EXIT_SUCCESS); } if (write_pwd[0]) { do_crypt(write_pwd, str); create_password(logbook, "Write Password", str); exit(EXIT_SUCCESS); } if (admin_pwd[0]) { do_crypt(admin_pwd, str); create_password(logbook, "Admin Password", str); exit(EXIT_SUCCESS); } /* extract resource directory from configuration file if not given */ if (config_file[0] && strchr(config_file, DIR_SEPARATOR) && !resource_dir[0]) { strcpy(resource_dir, config_file); for (i = strlen(resource_dir) - 1; i > 0; i--) { if (resource_dir[i] == DIR_SEPARATOR) break; resource_dir[i] = 0; } } /* do the same for the logbook dir */ if (config_file[0] && strchr(config_file, DIR_SEPARATOR) && !logbook_dir[0]) { strcpy(logbook_dir, config_file); for (i = strlen(logbook_dir) - 1; i > 0; i--) { if (logbook_dir[i] == DIR_SEPARATOR) break; logbook_dir[i] = 0; } strlcat(logbook_dir, "logbooks", sizeof(logbook_dir)); } /* set default logbook dir if not given */ if (!logbook_dir[0]) strcpy(logbook_dir, "logbooks"); if (resource_dir[0] && resource_dir[strlen(resource_dir) - 1] != DIR_SEPARATOR) strlcat(resource_dir, DIR_SEPARATOR_STR, sizeof(resource_dir)); if (logbook_dir[0] && logbook_dir[strlen(logbook_dir) - 1] != DIR_SEPARATOR) strlcat(logbook_dir, DIR_SEPARATOR_STR, sizeof(logbook_dir)); if (verbose) { printf("Config file : %s\n", config_file); printf("Resource dir : %s\n", resource_dir[0] ? resource_dir : "current dir"); printf("Logbook dir : %s\n", logbook_dir[0] ? logbook_dir : "current dir"); } /* get port from configuration file */ if (tcp_port_cl != 0) tcp_port = tcp_port_cl; else { if (getcfg("global", "Port", str)) tcp_port = atoi(str); } server_loop(tcp_port, daemon); exit(EXIT_SUCCESS); }
\n"); rsprintf("\n"); /* link to previous year */ rsprintf("  "); rsprintf("", index, cur_mon, cur_year - 1); rsprintf("\"%s\"", loc("Previous Year")); /* current year */ rsprintf(" %d ", cur_year); /* link to next year */ rsprintf("", index, cur_mon, cur_year + 1); rsprintf("\"%s\"", loc("Next Year")); /* go to first day of month */ ts->tm_mday = 1; stime = mktime(ts); /* go to last sunday */ stime = stime - 3600 * 24 * ts->tm_wday; rsprintf("
%s