/********************************************************************
Name: elogd.c
Created by: Stefan Ritt
Contents: Web server program for Electronic Logbook ELOG
$Id$
\********************************************************************/
#include "elogd.h"
char svn_revision[] = "$Id$";
/* ELOG identification */
static const char ELOGID[] = "elogd " VERSION " built " __DATE__ ", " __TIME__;
BOOL running_as_daemon; /* Running as a daemon/service? */
int elog_tcp_port; /* Server's TCP port */
static void (*printf_handler) (const char *); /* Handler to printf for logging */
static void (*fputs_handler) (const char *); /* Handler to fputs for logging */
static FILE *current_output_stream = NULL; /* Currently used output stream */
char *return_buffer;
int return_buffer_size;
int strlen_retbuf;
int keep_alive;
char header_buffer[20000];
int return_length;
char host_name[256];
char referer[256];
char browser[256];
char config_file[256];
char resource_dir[256];
char logbook_dir[256];
char listen_interface[256];
char theme_name[80];
char http_host[256];
char _param[MAX_PARAM][NAME_LENGTH];
char _value[MAX_PARAM][NAME_LENGTH];
char _mtext[TEXT_SIZE];
char _cmdline[CMD_SIZE];
char *_attachment_buffer;
int _attachment_size;
int _max_content_length = MAX_CONTENT_LENGTH;
struct in_addr rem_addr;
char rem_host[256];
char rem_host_ip[256];
int _sock;
BOOL use_keepalive, enable_execute = FALSE;
BOOL fckedit_exist, image_magick_exist;
int _verbose, _current_message_id;
int _logging_level, _ssl_flag;
LOGBOOK *lb_list = NULL;
#ifdef HAVE_SSL
SSL *_ssl_con;
#endif
char *mname[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September",
"October", "November", "December"
};
char type_list[MAX_N_LIST][NAME_LENGTH] = { "Routine", "Other" };
char category_list[MAX_N_LIST][NAME_LENGTH] = { "General", "Other",
};
char author_list[MAX_N_LIST][NAME_LENGTH] = { "" };
char attr_list[MAX_N_ATTR][NAME_LENGTH];
char attr_options[MAX_N_ATTR][MAX_N_LIST][NAME_LENGTH];
int attr_flags[MAX_N_ATTR];
char attr_list_default[][NAME_LENGTH] = { "Author", "Type", "Category", "Subject", "" };
char attr_options_default[][MAX_N_LIST][NAME_LENGTH] = { {""}, {"Routine", "Other"},
{"General", "Other"}, {""}
};
int attr_flags_default[] = { AF_REQUIRED, 0, 0, 0 };
struct {
char ext[32];
char type[80];
} filetype[] = {
{
".AI", "application/postscript"}, {
".ASC", "text/plain"}, {
".BZ2", "application/x-bzip2"}, {
".CFG", "text/plain"}, {
".CHRT", "application/x-kchart"}, {
".CONF", "text/plain"}, {
".CSH", "application/x-csh"}, {
".CSS", "text/css"}, {
".DOC", "application/msword"}, {
".DVI", "application/x-dvi"}, {
".EPS", "application/postscript"}, {
".GIF", "image/gif"}, {
".GZ", "application/x-gzip"}, {
".HTM", "text/html"}, {
".HTML", "text/html"}, {
".ICO", "image/x-icon"}, {
".JPEG", "image/jpeg"}, {
".JPG", "image/jpeg"}, {
".JS", "application/x-javascript"}, {
".KPR", "application/x-kpresenter"}, {
".KSP", "application/x-kspread"}, {
".KWD", "application/x-kword"}, {
".MP3", "audio/mpeg"}, {
".OGG", "application/x-ogg"}, {
".PDF", "application/pdf"}, {
".PNG", "image/png"}, {
".PS", "application/postscript"}, {
".RAM", "audio/x-pn-realaudio"}, {
".RM", "audio/x-pn-realaudio"}, {
".RM", "audio/x-pn-realaudio"}, {
".RM", "audio/x-pn-realaudio"}, {
".RPM", "application/x-rpm"}, {
".RTF", "application/rtf"}, {
".SH", "application/x-sh"}, {
".SVG", "image/svg+xml"}, {
".TAR", "application/x-tar"}, {
".TCL", "application/x-tcl"}, {
".TEX", "application/x-tex"}, {
".TGZ", "application/x-gzip"}, {
".TIF", "image/tiff"}, {
".TIFF", "image/tiff"}, {
".TXT", "text/plain"}, {
".WAV", "audio/x-wav"}, {
".XLS", "application/x-msexcel"}, {
".XML", "text/xml"}, {
".XSL", "text/xml"}, {
".ZIP", "application/x-zip-compressed"}, {
/* Open XML file types */
".DOCM", "application/vnd.ms-word.document.macroEnabled.12"}, {
".DOCX", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, {
".DOTM", "application/vnd.ms-word.template.macroEnabled.12"}, {
".DOTX", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"}, {
".PPSM", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"}, {
".PPSX", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"}, {
".PPTM", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"}, {
".PPTX", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, {
".XLSB", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"}, {
".XLSM", "application/vnd.ms-excel.sheet.macroEnabled.12"}, {
".XLSX", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, {
".XPS", "application/vnd.ms-xpsdocument"}, {
"", ""},};
#ifdef OS_WINNT
int run_service(void);
#endif
/*---- Funcions from the MIDAS library -----------------------------*/
#define my_toupper(_c) ( ((_c)>='a' && (_c)<='z') ? ((_c)-'a'+'A') : (_c) )
#define my_tolower(_c) ( ((_c)>='A' && (_c)<='Z') ? ((_c)-'A'+'a') : (_c) )
BOOL strieq(const char *str1, const char *str2)
{
char c1, c2;
if (str1 == NULL && str2 == NULL)
return TRUE;
if (str1 == NULL || str2 == NULL)
return FALSE;
if (strlen(str1) != strlen(str2))
return FALSE;
while (*str1) {
c1 = *str1++;
c2 = *str2++;
if (my_toupper(c1) != my_toupper(c2))
return FALSE;
}
if (*str2)
return FALSE;
return TRUE;
}
BOOL strnieq(const char *str1, const char *str2, int n)
{
char c1, c2;
int i;
if (str1 == NULL && str2 == NULL && n == 0)
return TRUE;
if (str1 == NULL || str2 == NULL)
return FALSE;
if ((int) strlen(str1) < n || (int) strlen(str2) < n)
return FALSE;
for (i = 0; i < n && *str1; i++) {
c1 = *str1++;
c2 = *str2++;
if (my_toupper(c1) != my_toupper(c2))
return FALSE;
}
if (i < n)
return FALSE;
return TRUE;
}
char *stristr(const char *str, const char *pattern)
{
char c1, c2, *ps, *pp;
if (str == NULL || pattern == NULL)
return NULL;
while (*str) {
ps = (char *) str;
pp = (char *) pattern;
c1 = *ps;
c2 = *pp;
if (my_toupper(c1) == my_toupper(c2)) {
while (*pp) {
c1 = *ps;
c2 = *pp;
if (my_toupper(c1) != my_toupper(c2))
break;
ps++;
pp++;
}
if (!*pp)
return (char *) str;
}
str++;
}
return NULL;
}
void strextract(const char *str, char delim, char *extr, int size)
/* extract a substinr "extr" from "str" until "delim" is found */
{
int i;
for (i = 0; str[i] != delim && i < size - 1; i++)
extr[i] = str[i];
extr[i] = 0;
}
static BOOL chkext(const char *str, const char *ext)
{
int extl, strl;
char c1, c2;
if (ext == NULL || str == NULL)
return FALSE;
extl = strlen(ext);
strl = strlen(str);
if (extl >= strl)
return FALSE;
str = str + strl - extl;
while (*str) {
c1 = *str++;
c2 = *ext++;
if (my_toupper(c1) != my_toupper(c2))
return FALSE;
}
return TRUE;
}
int is_verbose(void)
{
return _verbose;
}
void set_verbose(int v)
{
_verbose = v;
}
/* workaround for some gcc versions bug for "%c" format (see strftime(3) */
size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
{
return strftime(s, max, fmt, tm);
}
/* signal save read function */
int my_read(int fh, void *buffer, unsigned int bytes)
{
#ifdef OS_UNIX
int i, n = 0;
do {
i = read(fh, (char *) buffer + n, bytes - n);
/* don't return if an alarm signal was cought */
if (i == -1 && errno == EINTR)
continue;
if (i == -1)
return -1;
if (i == 0)
return n;
n += i;
} while (n < (int) bytes);
return n;
#else
return read(fh, buffer, bytes);
#endif
return 0;
}
/* workaround for wong timezone under MAX OSX */
long my_timezone()
{
#if defined(OS_MACOSX) || defined(__FreeBSD__) || defined(__OpenBSD__)
time_t tp;
time(&tp);
return -localtime(&tp)->tm_gmtoff;
#else
return timezone;
#endif
}
/*---- Compose RFC2822 compliant date ---*/
void get_rfc2822_date(char *date, int size, time_t ltime)
{
time_t now;
char buf[256];
int offset;
struct tm *ts;
/* switch locale temporarily back to english to comply with RFC2822 date format */
setlocale(LC_ALL, "C");
if (ltime == 0)
time(&now);
else
now = ltime;
ts = localtime(&now);
assert(ts);
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", ts);
offset = (-(int) my_timezone());
if (ts->tm_isdst)
offset += 3600;
snprintf(date, size - 1, "%s %+03d%02d", buf, (int) (offset / 3600),
(int) ((abs((int) offset) / 60) % 60));
}
/*---- Safe malloc wrappers with out of memory checking from GNU ---*/
static void memory_error_and_abort(char *func)
{
eprintf("%s: not enough memory\n", func);
exit(EXIT_FAILURE);
}
/* Return a pointer to free()able block of memory large enough
to hold BYTES number of bytes. If the memory cannot be allocated,
print an error message and abort. */
void *xmalloc(size_t bytes)
{
char *temp;
/* Align buffer on 4 byte boundery for HP UX and other 64 bit systems to prevent Bus error (core dump) */
if (bytes & 3)
bytes += 4 - (bytes & 3);
temp = (char *) malloc(bytes + 12);
if (temp == 0)
memory_error_and_abort("xmalloc");
/* put magic number around array and put array size */
*(unsigned int *) (temp + 0) = bytes;
*(unsigned int *) (temp + 4) = 0xdeadc0de;
*(unsigned int *) (temp + bytes + 8) = 0xdeadc0de;
return (temp + 8);
}
void *xcalloc(size_t count, size_t bytes)
{
char *temp;
/* Align buffer on 4 byte boundery for HP UX and other 64 bit systems to prevent Bus error (core dump) */
if (bytes & 3)
bytes += 4 - (bytes & 3);
temp = (char *) malloc(count * bytes + 12);
if (temp == 0)
memory_error_and_abort("xcalloc");
memset(temp, 0, count * bytes + 12);
/* put magic number around array */
*(unsigned int *) (temp + 0) = count * bytes;
*(unsigned int *) (temp + 4) = 0xdeadc0de;
*(unsigned int *) (temp + count * bytes + 8) = 0xdeadc0de;
return (temp + 8);
}
void *xrealloc(void *pointer, size_t bytes)
{
char *temp;
int old_size;
/* Align buffer on 4 byte boundery for HP UX and other 64 bit systems to prevent Bus error (core dump) */
if (bytes & 3)
bytes += 4 - (bytes & 3);
if (pointer == NULL)
return xmalloc(bytes);
/* check old magic number */
temp = pointer;
assert(*((unsigned int *) (temp - 4)) == 0xdeadc0de);
old_size = *((unsigned int *) (temp - 8));
assert(*((unsigned int *) (temp + old_size)) == 0xdeadc0de);
temp = (char *) realloc(temp - 8, bytes + 12);
if (temp == 0)
memory_error_and_abort("xrealloc");
/* put magic number around array */
*(unsigned int *) (temp + 0) = bytes;
*(unsigned int *) (temp + 4) = 0xdeadc0de;
*(unsigned int *) (temp + bytes + 8) = 0xdeadc0de;
return (temp + 8);
}
void xfree(void *pointer)
{
char *temp;
int old_size;
if (!pointer)
return;
/* check for magic byte */
temp = pointer;
assert(*((unsigned int *) (temp - 4)) == 0xdeadc0de);
old_size = *((unsigned int *) (temp - 8));
assert(*((unsigned int *) (temp + old_size)) == 0xdeadc0de);
free(temp - 8);
}
char *xstrdup(const char *string)
{
char *s;
s = (char *) xmalloc(strlen(string) + 1);
strcpy(s, string);
return s;
}
/*----------------------- Message handling -------------------------*/
/* Have vasprintf? (seems that only libc6 based Linux has this) */
#ifdef __linux__
#define HAVE_VASPRintF
#endif
#ifndef HAVE_VASPRintF
/* vasprintf implementation taken (and adapted) from GNU libiberty */
static int int_vasprintf(char **result, const char *format, va_list args)
{
const char *p = format;
/* Add one to make sure that it is never zero, which might cause malloc
to return NULL. */
int total_width = strlen(format) + 1;
va_list ap;
#ifdef va_copy
va_copy(ap, args);
#else
memcpy(&ap, &args, sizeof(va_list));
#endif
while (*p != '\0') {
if (*p++ == '%') {
while (strchr("-+ #0", *p))
++p;
if (*p == '*') {
++p;
total_width += abs(va_arg(ap, int));
} else
total_width += strtoul(p, (char **) &p, 10);
if (*p == '.') {
++p;
if (*p == '*') {
++p;
total_width += abs(va_arg(ap, int));
} else
total_width += strtoul(p, (char **) &p, 10);
}
while (strchr("hlL", *p))
++p;
/*
* Should be big enough for any format specifier
* except %s and floats.
*/
total_width += 30;
switch (*p) {
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
case 'c':
(void) va_arg(ap, int);
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
(void) va_arg(ap, double);
/*
* Since an ieee double can have an exponent of 307, we'll
* make the buffer wide enough to cover the gross case.
*/
total_width += 307;
break;
case 's':
total_width += strlen(va_arg(ap, char *));
break;
case 'p':
case 'n':
(void) va_arg(ap, char *);
break;
}
p++;
}
}
#ifdef va_copy
va_end(ap);
#endif
*result = (char *) malloc(total_width);
if (*result != NULL)
return vsprintf(*result, format, args);
else
return -1;
}
#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
int vasprintf(char **result, const char *format, _BSD_VA_LIST_ args)
#else
int vasprintf(char **result, const char *format, va_list args)
#endif
{
return int_vasprintf(result, format, args);
}
#endif /* ! HAVE_VASPRintF */
/* Safe replacement for vasprintf (adapted code from Samba) */
int xvasprintf(char **ptr, const char *format, va_list ap)
{
int n;
va_list save;
#ifdef va_copy
va_copy(save, ap);
#else
#ifdef __va_copy
__va_copy(save, ap);
#else
save = ap;
#endif
#endif
n = vasprintf(ptr, format, save);
if (n == -1 || !*ptr) {
printf("Not enough memory");
exit(EXIT_FAILURE);
}
return n;
}
/* Driver for printf_handler, drop-in replacement for printf */
void eprintf(const char *format, ...)
{
va_list ap;
char *msg;
va_start(ap, format);
xvasprintf(&msg, format, ap);
va_end(ap);
(*printf_handler) (msg);
free(msg);
}
/* Driver for fputs_handler, drop-in replacement for fputs(buf, fd) */
void efputs(const char *buf)
{
(*fputs_handler) (buf);
}
/* Dump with the newline, drop-in replacement for puts(buf) */
void eputs(const char *buf)
{
char *p;
p = xmalloc(strlen(buf) + 2);
strcpy(p, buf);
strcat(p, "\n");
(*fputs_handler) (p);
xfree(p);
}
/* Flush the current output stream */
void eflush(void)
{
/* Do this only for non-NULL streams (uninitiated stream or a syslog) */
if (current_output_stream != NULL)
fflush(current_output_stream);
}
#ifdef OS_WINNT
HANDLE hEventLog;
#endif
/* Print MSG to syslog */
void print_syslog(const char *msg)
{
char *p;
/* strip trailing \r and \n */
p = xstrdup(msg);
while (p[strlen(p) - 1] == '\r' || p[strlen(p) - 1] == '\n')
p[strlen(p) - 1] = 0;
#ifdef OS_UNIX
syslog(SYSLOG_PRIORITY, "%s", p);
#else
ReportEvent(hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, &p, NULL);
#endif
xfree(p);
}
/* Print MSG to stderr */
void print_stderr(const char *msg)
{
fprintf(stderr, "%s", msg);
}
/* Dump BUF to syslog */
void fputs_syslog(const char *buf)
{
char *p;
/* strip trailing \r and \n */
p = xstrdup(buf);
while (p[strlen(p) - 1] == '\r' || p[strlen(p) - 1] == '\n')
p[strlen(p) - 1] = 0;
#ifdef OS_UNIX
syslog(SYSLOG_PRIORITY, "%s", p);
#else
ReportEvent(hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, &p, NULL);
#endif
xfree(p);
}
/* Dump BUF to stderr */
void fputs_stderr(const char *buf)
{
fputs(buf, stderr);
}
/* Redirect all messages handled with eprintf/efputs
to syslog (Unix) or event log (Windows) */
void redirect_to_syslog(void)
{
static int has_inited = 0;
/* initiate syslog */
if (!has_inited) {
#ifdef OS_UNIX
setlogmask(LOG_UPTO(SYSLOG_PRIORITY));
openlog("elogd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
#else
hEventLog = RegisterEventSource(NULL, "ELOG");
#endif
}
has_inited = 1;
printf_handler = print_syslog;
fputs_handler = fputs_syslog;
/* tells that the syslog facility is currently used as output */
current_output_stream = NULL;
}
/* Redirect all messages handled with eprintf/efputs to stderr */
void redirect_to_stderr(void)
{
printf_handler = print_stderr;
fputs_handler = fputs_stderr;
current_output_stream = stderr;
}
/*------------------------------------------------------------------*/
int my_shell(char *cmd, char *result, int size)
{
#ifdef OS_WINNT
HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
hChildStdoutRd, hChildStdoutWr, hChildStderrRd, hChildStderrWr, hSaveStdin, hSaveStdout, hSaveStderr;
SECURITY_ATTRIBUTES saAttr;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
char buffer[10000];
DWORD dwRead, dwAvail, i;
/* Set the bInheritHandle flag so pipe handles are inherited. */
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
/* Save the handle to the current STDOUT. */
hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
/* Create a pipe for the child's STDOUT. */
if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
return 0;
/* Set a write handle to the pipe to be STDOUT. */
if (!SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
return 0;
/* Save the handle to the current STDERR. */
hSaveStderr = GetStdHandle(STD_ERROR_HANDLE);
/* Create a pipe for the child's STDERR. */
if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0))
return 0;
/* Set a read handle to the pipe to be STDERR. */
if (!SetStdHandle(STD_ERROR_HANDLE, hChildStderrWr))
return 0;
/* Save the handle to the current STDIN. */
hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
/* Create a pipe for the child's STDIN. */
if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
return 0;
/* Set a read handle to the pipe to be STDIN. */
if (!SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
return 0;
/* Duplicate the write handle to the pipe so it is not inherited. */
if (!DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, /* not inherited */
DUPLICATE_SAME_ACCESS))
return 0;
CloseHandle(hChildStdinWr);
/* Now create the child process. */
memset(&siStartInfo, 0, sizeof(siStartInfo));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.lpReserved = NULL;
siStartInfo.lpReserved2 = NULL;
siStartInfo.cbReserved2 = 0;
siStartInfo.lpDesktop = NULL;
siStartInfo.dwFlags = 0;
/* command to execute */
sprintf(buffer, "cmd /q /c %s", cmd);
if (!CreateProcess(NULL, buffer, /* command line */
NULL, /* process security attributes */
NULL, /* primary thread security attributes */
TRUE, /* handles are inherited */
0, /* creation flags */
NULL, /* use parent's environment */
NULL, /* use parent's current directory */
&siStartInfo, /* STARTUPINFO pointer */
&piProcInfo)) /* receives PROCESS_INFORMATION */
return 0;
/* After process creation, restore the saved STDIN and STDOUT. */
SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);
SetStdHandle(STD_ERROR_HANDLE, hSaveStderr);
memset(result, 0, size);
do {
/* query stdout */
do {
if (!PeekNamedPipe(hChildStdoutRd, buffer, 256, &dwRead, &dwAvail, NULL))
break;
if (dwRead > 0) {
ReadFile(hChildStdoutRd, buffer, 256, &dwRead, NULL);
buffer[dwRead] = 0;
strlcat(result, buffer, size);
}
} while (dwAvail > 0);
/* query stderr */
do {
if (!PeekNamedPipe(hChildStderrRd, buffer, 256, &dwRead, &dwAvail, NULL))
break;
if (dwRead > 0) {
ReadFile(hChildStderrRd, buffer, 256, &dwRead, NULL);
buffer[dwRead] = 0;
strlcat(result, buffer, size);
}
} while (dwAvail > 0);
/* check if subprocess still alive */
if (!GetExitCodeProcess(piProcInfo.hProcess, &i))
break;
if (i != STILL_ACTIVE)
break;
/* give some CPU to subprocess */
Sleep(10);
} while (TRUE);
CloseHandle(hChildStdinWrDup);
CloseHandle(hChildStdinRd);
CloseHandle(hChildStderrRd);
CloseHandle(hChildStdoutRd);
/* strip trailing CR/LF */
while (strlen(result) > 0 && (result[strlen(result) - 1] == '\r' || result[strlen(result) - 1] == '\n'))
result[strlen(result) - 1] = 0;
return 1;
#endif /* OS_WINNT */
#ifdef OS_UNIX
pid_t child_pid;
int fh, status, i;
char str[256];
if ((child_pid = fork()) < 0)
return 0;
else if (child_pid > 0) {
/* parent process waits for child */
waitpid(child_pid, &status, 0);
/* read back result */
memset(result, 0, size);
fh = open("/tmp/elog-shell", O_RDONLY);
if (fh > 0) {
i = read(fh, result, size);
close(fh);
}
/* remove temporary file */
remove("/tmp/elog-shell");
/* strip trailing CR/LF */
while (strlen(result) > 0 && (result[strlen(result) - 1] == '\r' || result[strlen(result) - 1] == '\n'))
result[strlen(result) - 1] = 0;
} else {
/* child process */
/* restore original UID/GID */
if (setregid(-1, orig_gid) < 0 || setreuid(-1, orig_uid) < 0)
eprintf("Cannot restore original GID/UID.\n");
/* give up root privilege permanently */
if (geteuid() == 0) {
if (!getcfg("global", "Grp", str, sizeof(str)) || setgroup(str) < 0) {
eprintf("Falling back to default group \"elog\"\n");
if (setgroup("elog") < 0) {
eprintf("Falling back to default group \"%s\"\n", DEFAULT_GROUP);
if (setgroup(DEFAULT_GROUP) < 0) {
eprintf("Refuse to run as setgid root.\n");
eprintf("Please consider to define a Grp statement in configuration file\n");
exit(EXIT_FAILURE);
}
}
} else if (is_verbose())
eprintf("Falling back to group \"%s\"\n", str);
if (!getcfg("global", "Usr", str, sizeof(str)) || setuser(str) < 0) {
eprintf("Falling back to default user \"elog\"\n");
if (setuser("elog") < 0) {
eprintf("Falling back to default user \"%s\"\n", DEFAULT_USER);
if (setuser(DEFAULT_USER) < 0) {
eprintf("Refuse to run as setuid root.\n");
eprintf("Please consider to define a Usr statement in configuration file\n");
exit(EXIT_FAILURE);
}
}
} else if (is_verbose())
eprintf("Falling back to user \"%s\"\n", str);
}
/* execute shell with redirection to /tmp/elog-shell */
sprintf(str, "/bin/sh -c \"%s\" > /tmp/elog-shell 2>&1", cmd);
if (is_verbose()) {
efputs("Going to execute: ");
efputs(str);
efputs("\n");
}
system(str);
_exit(0);
}
return 1;
#endif /* OS_UNIX */
}
/*------------------------------------------------------------------*/
void strsubst_list(char *string, int size, char name[][NAME_LENGTH], char value[][NAME_LENGTH], int n)
/* subsitute "$name" with value corresponding to name */
{
int i, j;
char tmp[2 * NAME_LENGTH], str[2 * NAME_LENGTH], uattr[2 * NAME_LENGTH], *ps, *pt, *p, result[10000];
pt = tmp;
ps = string;
for (p = strchr(ps, '$'); p != NULL; p = strchr(ps, '$')) {
/* copy leading characters */
j = (int) (p - ps);
if (j >= (int) sizeof(tmp))
return;
memcpy(pt, ps, j);
pt += j;
p++;
/* extract name */
strlcpy(str, p, sizeof(str));
for (j = 0; j < (int) strlen(str); j++)
str[j] = toupper(str[j]);
/* do shell substituion at the end, so that shell parameter can
contain substituted attributes */
if (strncmp(str, "SHELL(", 6) == 0) {
strlcpy(pt, "$shell(", sizeof(tmp) - (pt - tmp));
ps += 7;
pt += 7;
continue;
}
/* search name */
for (i = 0; i < n; i++) {
strlcpy(uattr, name[i], sizeof(uattr));
for (j = 0; j < (int) strlen(uattr); j++)
uattr[j] = toupper(uattr[j]);
if (strncmp(str, uattr, strlen(uattr)) == 0)
break;
}
/* copy value */
if (i < n) {
strlcpy(pt, value[i], sizeof(tmp) - (pt - tmp));
pt += strlen(pt);
ps = p + strlen(uattr);
} else {
*pt++ = '$';
ps = p;
}
}
/* copy remainder */
strlcpy(pt, ps, sizeof(tmp) - (pt - tmp));
strlcpy(string, tmp, size);
/* check for $shell() subsitution */
pt = tmp;
ps = string;
for (p = strchr(ps, '$'); p != NULL; p = strchr(ps, '$')) {
/* copy leading characters */
j = (int) (p - ps);
if (j >= (int) sizeof(tmp))
return;
memcpy(pt, ps, j);
pt += j;
p++;
/* extract name */
strlcpy(str, p, sizeof(str));
for (j = 0; j < (int) strlen(str); j++)
str[j] = toupper(str[j]);
if (strncmp(str, "SHELL(", 6) == 0) {
ps += 7;
if (strrchr(p, '\"')) {
ps += strrchr(p, '\"') - p - 5;
if (strchr(ps, ')'))
ps = strchr(ps, ')') + 1;
} else {
if (strchr(ps, ')'))
ps = strchr(ps, ')') + 1;
}
if (str[6] == '"') {
strcpy(str, p + 7);
if (strrchr(str, '\"'))
*strrchr(str, '\"') = 0;
} else {
strcpy(str, p + 6);
if (strrchr(str, ')'))
*strrchr(str, ')') = 0;
}
if (!enable_execute) {
strlcpy(result, loc("Shell execution not enabled via -x flag"), sizeof(result));
eprintf("Shell execution not enabled via -x flag.\n");
} else
my_shell(str, result, sizeof(result));
strlcpy(pt, result, sizeof(tmp) - (pt - tmp));
pt += strlen(pt);
} else {
*pt++ = '$';
ps = p;
}
}
/* copy remainder */
strlcpy(pt, ps, sizeof(tmp) - (pt - tmp));
/* return result */
strlcpy(string, tmp, size);
}
/*------------------------------------------------------------------*/
void strsubst(char *string, int size, char *pattern, char *subst)
/* subsitute "pattern" with "subst" in "string" */
{
char *tail, *p;
int s;
p = string;
for (p = stristr(p, pattern); p != NULL; p = stristr(p, pattern)) {
if (strlen(pattern) == strlen(subst)) {
memcpy(p, subst, strlen(subst));
} else if (strlen(pattern) > strlen(subst)) {
memcpy(p, subst, strlen(subst));
memmove(p + strlen(subst), p + strlen(pattern), strlen(p + strlen(pattern)) + 1);
} else {
tail = (char *) xmalloc(strlen(p) - strlen(pattern) + 1);
strcpy(tail, p + strlen(pattern));
s = size - (p - string);
strlcpy(p, subst, s);
strlcat(p, tail, s);
xfree(tail);
}
p += strlen(subst);
}
}
/*------------------------------------------------------------------*/
void url_decode(char *p)
/********************************************************************\
Decode the given string in-place by expanding %XX escapes
\********************************************************************/
{
char *pD, str[3];
int i;
pD = p;
while (*p) {
if (*p == '%') {
/* Escape: next 2 chars are hex representation of the actual character */
p++;
if (isxdigit(p[0]) && isxdigit(p[1])) {
str[0] = p[0];
str[1] = p[1];
str[2] = 0;
sscanf(p, "%02X", &i);
*pD++ = (char) i;
p += 2;
} else
*pD++ = '%';
} else if (*p == '+') {
/* convert '+' to ' ' */
*pD++ = ' ';
p++;
} else {
*pD++ = *p++;
}
}
*pD = '\0';
}
void url_encode(char *ps, int size)
/********************************************************************\
Encode the given string in-place by adding %XX escapes
\********************************************************************/
{
unsigned char *pd, *p;
unsigned char str[NAME_LENGTH];
pd = str;
p = (unsigned char *) ps;
while (*p && pd < str + 250) {
if (strchr("%&=#?+<>", *p) || *p > 127) {
sprintf((char *) pd, "%%%02X", *p);
pd += 3;
p++;
} else if (*p == ' ') {
*pd++ = '+';
p++;
} else {
*pd++ = *p++;
}
}
*pd = '\0';
strlcpy(ps, (char *) str, size);
}
void url_slash_encode(char *ps, int size)
/********************************************************************\
Do the same including '/' characters
\********************************************************************/
{
unsigned char *pd, *p;
unsigned char str[NAME_LENGTH];
pd = str;
p = (unsigned char *) ps;
while (*p && pd < str + 250) {
if (strchr("%&=#?+<>/", *p) || *p > 127) {
sprintf((char *) pd, "%%%02X", *p);
pd += 3;
p++;
} else if (*p == ' ') {
*pd++ = '+';
p++;
} else {
*pd++ = *p++;
}
}
*pd = '\0';
strlcpy(ps, (char *) str, size);
}
/*-------------------------------------------------------------------*/
void str_escape(char *ps, int size)
/********************************************************************\
Encode the given string in-place by adding \\ escapes for `$"\
\********************************************************************/
{
unsigned char *pd, *p;
unsigned char str[NAME_LENGTH];
pd = str;
p = (unsigned char *) ps;
while (*p && pd < str + 250) {
if (strchr("'$\"\\", *p)) {
*pd++ = '\\';
*pd++ = *p++;
} else {
*pd++ = *p++;
}
}
*pd = '\0';
strlcpy(ps, (char *) str, size);
}
void btou(char *str)
/* convert all blanks to underscores in a string */
{
int i;
for (i = 0; i < (int) strlen(str); i++)
if (str[i] == ' ')
str[i] = '_';
}
/*-------------------------------------------------------------------*/
void stou(char *str)
/* convert all special characters to underscores in a string */
{
int i;
for (i = 0; i < (int) strlen(str); i++)
if (!isalnum(str[i]))
str[i] = '_';
}
/*-------------------------------------------------------------------*/
char *map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int cind(char c)
{
int i;
if (c == '=')
return 0;
for (i = 0; i < 64; i++)
if (map[i] == c)
return i;
return -1;
}
void base64_decode(char *s, char *d)
{
unsigned int t;
while (s && *s) {
t = cind(*s) << 18;
s++;
t |= cind(*s) << 12;
s++;
t |= cind(*s) << 6;
s++;
t |= cind(*s) << 0;
s++;
*(d + 2) = (char) (t & 0xFF);
t >>= 8;
*(d + 1) = (char) (t & 0xFF);
t >>= 8;
*d = (char) (t & 0xFF);
d += 3;
}
*d = 0;
}
void base64_encode(unsigned char *s, unsigned char *d, int size)
{
unsigned int t, pad;
unsigned char *p;
pad = 3 - strlen((char *) s) % 3;
if (pad == 3)
pad = 0;
p = d;
while (*s) {
t = (*s++) << 16;
if (*s)
t |= (*s++) << 8;
if (*s)
t |= (*s++) << 0;
*(d + 3) = map[t & 63];
t >>= 6;
*(d + 2) = map[t & 63];
t >>= 6;
*(d + 1) = map[t & 63];
t >>= 6;
*(d + 0) = map[t & 63];
d += 4;
if (d - p >= size - 3)
return;
}
*d = 0;
while (pad--)
*(--d) = '=';
}
void base64_bufenc(unsigned char *s, int len, char *d)
{
unsigned int t, pad;
int i;
pad = 3 - len % 3;
if (pad == 3)
pad = 0;
for (i = 0; i < len;) {
t = s[i++] << 16;
if (i < len)
t |= s[i++] << 8;
if (i < len)
t |= s[i++] << 0;
*(d + 3) = map[t & 63];
t >>= 6;
*(d + 2) = map[t & 63];
t >>= 6;
*(d + 1) = map[t & 63];
t >>= 6;
*(d + 0) = map[t & 63];
d += 4;
}
*d = 0;
while (pad--)
*(--d) = '=';
}
char *sha256_crypt(const char *key, const char *salt);
void do_crypt(const char *s, char *d, int size)
{
strlcpy(d, sha256_crypt(s, "$5$") + 4, size);
}
/*------------------------------------------------------------------*
MD5 Checksum Routines
\*------------------------------------------------------------------*/
typedef struct {
unsigned int state[4]; // state (ABCD)
unsigned int count[2]; // number of bits, modulo 2^64 (lsb first)
unsigned char buffer[64]; // input buffer
} MD5_CONTEXT;
/*------------------------------------------------------------------*/
/* prototypes of the support routines */
void _MD5_update(MD5_CONTEXT *, const void *, unsigned int);
void _MD5_transform(unsigned int[4], unsigned char[64]);
void _MD5_encode(unsigned char *, unsigned int *, unsigned int);
void _MD5_decode(unsigned int *, unsigned char *, unsigned int);
/* F, G, H and I are basic MD5 functions */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/*------------------------------------------------------------------*/
/* main MD5 checksum routine, returns digest from pdata buffer */
void MD5_checksum(const void *pdata, unsigned int len, unsigned char digest[16])
{
MD5_CONTEXT ctx;
unsigned char bits[8];
unsigned int i, padlen;
/* to allow multithreading we have to locate the padding memory here */
unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0
};
memset(&ctx, 0, sizeof(MD5_CONTEXT));
ctx.count[0] = ctx.count[1] = 0;
/* load magic initialization constants */
ctx.state[0] = 0x67452301;
ctx.state[1] = 0xefcdab89;
ctx.state[2] = 0x98badcfe;
ctx.state[3] = 0x10325476;
_MD5_update(&ctx, pdata, len);
// save number of bits
_MD5_encode(bits, ctx.count, 8);
// pad out to 56 mod 64
i = (unsigned int) ((ctx.count[0] >> 3) & 0x3f);
padlen = (i < 56) ? (56 - i) : (120 - i);
_MD5_update(&ctx, PADDING, padlen);
// append length (before padding)
_MD5_update(&ctx, bits, 8);
// store state in digest
_MD5_encode(digest, ctx.state, 16);
}
/*------------------------------------------------------------------*/
void _MD5_update(MD5_CONTEXT * pctx, const void *pdata, unsigned int len)
{
unsigned char *pin;
unsigned int i, index, partlen;
pin = (unsigned char *) pdata;
// compute number of bytes mod 64
index = (unsigned int) ((pctx->count[0] >> 3) & 0x3F);
// update number of bits
if ((pctx->count[0] += ((unsigned int) len << 3)) < ((unsigned int) len << 3))
pctx->count[1]++;
pctx->count[1] += ((unsigned int) len >> 29);
partlen = 64 - index;
// transform as many times as possible.
if (len >= partlen) {
memcpy(&pctx->buffer[index], pin, partlen);
_MD5_transform(pctx->state, pctx->buffer);
for (i = partlen; i + 63 < len; i += 64)
_MD5_transform(pctx->state, &pin[i]);
index = 0;
} else
i = 0;
/* buffer remaining input */
memcpy(&pctx->buffer[index], &pin[i], len - i);
}
/*------------------------------------------------------------------*/
/* basic transformation, transforms state based on block */
void _MD5_transform(unsigned int state[4], unsigned char block[64])
{
unsigned int lA = state[0], lB = state[1], lC = state[2], lD = state[3];
unsigned int x[16];
_MD5_decode(x, block, 64);
/* round 1 */
FF(lA, lB, lC, lD, x[0], 7, 0xd76aa478); // 1
FF(lD, lA, lB, lC, x[1], 12, 0xe8c7b756); // 2
FF(lC, lD, lA, lB, x[2], 17, 0x242070db); // 3
FF(lB, lC, lD, lA, x[3], 22, 0xc1bdceee); // 4
FF(lA, lB, lC, lD, x[4], 7, 0xf57c0faf); // 5
FF(lD, lA, lB, lC, x[5], 12, 0x4787c62a); // 6
FF(lC, lD, lA, lB, x[6], 17, 0xa8304613); // 7
FF(lB, lC, lD, lA, x[7], 22, 0xfd469501); // 8
FF(lA, lB, lC, lD, x[8], 7, 0x698098d8); // 9
FF(lD, lA, lB, lC, x[9], 12, 0x8b44f7af); // 10
FF(lC, lD, lA, lB, x[10], 17, 0xffff5bb1); // 11
FF(lB, lC, lD, lA, x[11], 22, 0x895cd7be); // 12
FF(lA, lB, lC, lD, x[12], 7, 0x6b901122); // 13
FF(lD, lA, lB, lC, x[13], 12, 0xfd987193); // 14
FF(lC, lD, lA, lB, x[14], 17, 0xa679438e); // 15
FF(lB, lC, lD, lA, x[15], 22, 0x49b40821); // 16
/* round 2 */
GG(lA, lB, lC, lD, x[1], 5, 0xf61e2562); // 17
GG(lD, lA, lB, lC, x[6], 9, 0xc040b340); // 18
GG(lC, lD, lA, lB, x[11], 14, 0x265e5a51); // 19
GG(lB, lC, lD, lA, x[0], 20, 0xe9b6c7aa); // 20
GG(lA, lB, lC, lD, x[5], 5, 0xd62f105d); // 21
GG(lD, lA, lB, lC, x[10], 9, 0x2441453); // 22
GG(lC, lD, lA, lB, x[15], 14, 0xd8a1e681); // 23
GG(lB, lC, lD, lA, x[4], 20, 0xe7d3fbc8); // 24
GG(lA, lB, lC, lD, x[9], 5, 0x21e1cde6); // 25
GG(lD, lA, lB, lC, x[14], 9, 0xc33707d6); // 26
GG(lC, lD, lA, lB, x[3], 14, 0xf4d50d87); // 27
GG(lB, lC, lD, lA, x[8], 20, 0x455a14ed); // 28
GG(lA, lB, lC, lD, x[13], 5, 0xa9e3e905); // 29
GG(lD, lA, lB, lC, x[2], 9, 0xfcefa3f8); // 30
GG(lC, lD, lA, lB, x[7], 14, 0x676f02d9); // 31
GG(lB, lC, lD, lA, x[12], 20, 0x8d2a4c8a); // 32
/* round 3 */
HH(lA, lB, lC, lD, x[5], 4, 0xfffa3942); // 33
HH(lD, lA, lB, lC, x[8], 11, 0x8771f681); // 34
HH(lC, lD, lA, lB, x[11], 16, 0x6d9d6122); // 35
HH(lB, lC, lD, lA, x[14], 23, 0xfde5380c); // 36
HH(lA, lB, lC, lD, x[1], 4, 0xa4beea44); // 37
HH(lD, lA, lB, lC, x[4], 11, 0x4bdecfa9); // 38
HH(lC, lD, lA, lB, x[7], 16, 0xf6bb4b60); // 39
HH(lB, lC, lD, lA, x[10], 23, 0xbebfbc70); // 40
HH(lA, lB, lC, lD, x[13], 4, 0x289b7ec6); // 41
HH(lD, lA, lB, lC, x[0], 11, 0xeaa127fa); // 42
HH(lC, lD, lA, lB, x[3], 16, 0xd4ef3085); // 43
HH(lB, lC, lD, lA, x[6], 23, 0x4881d05); // 44
HH(lA, lB, lC, lD, x[9], 4, 0xd9d4d039); // 45
HH(lD, lA, lB, lC, x[12], 11, 0xe6db99e5); // 46
HH(lC, lD, lA, lB, x[15], 16, 0x1fa27cf8); // 47
HH(lB, lC, lD, lA, x[2], 23, 0xc4ac5665); // 48
/* round 4 */
II(lA, lB, lC, lD, x[0], 6, 0xf4292244); // 49
II(lD, lA, lB, lC, x[7], 10, 0x432aff97); // 50
II(lC, lD, lA, lB, x[14], 15, 0xab9423a7); // 51
II(lB, lC, lD, lA, x[5], 21, 0xfc93a039); // 52
II(lA, lB, lC, lD, x[12], 6, 0x655b59c3); // 53
II(lD, lA, lB, lC, x[3], 10, 0x8f0ccc92); // 54
II(lC, lD, lA, lB, x[10], 15, 0xffeff47d); // 55
II(lB, lC, lD, lA, x[1], 21, 0x85845dd1); // 56
II(lA, lB, lC, lD, x[8], 6, 0x6fa87e4f); // 57
II(lD, lA, lB, lC, x[15], 10, 0xfe2ce6e0); // 58
II(lC, lD, lA, lB, x[6], 15, 0xa3014314); // 59
II(lB, lC, lD, lA, x[13], 21, 0x4e0811a1); // 60
II(lA, lB, lC, lD, x[4], 6, 0xf7537e82); // 61
II(lD, lA, lB, lC, x[11], 10, 0xbd3af235); // 62
II(lC, lD, lA, lB, x[2], 15, 0x2ad7d2bb); // 63
II(lB, lC, lD, lA, x[9], 21, 0xeb86d391); // 64
state[0] += lA;
state[1] += lB;
state[2] += lC;
state[3] += lD;
/* lClear sensitive information */
memset(x, 0, sizeof(x));
}
/*------------------------------------------------------------------*/
/* encodes input (unsigned int) into output (unsigned char),
assumes that lLen is a multiple of 4 */
void _MD5_encode(unsigned char *pout, unsigned int *pin, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
pout[j] = (unsigned char) (pin[i] & 0x0ff);
pout[j + 1] = (unsigned char) ((pin[i] >> 8) & 0x0ff);
pout[j + 2] = (unsigned char) ((pin[i] >> 16) & 0x0ff);
pout[j + 3] = (unsigned char) ((pin[i] >> 24) & 0x0ff);
}
}
/*------------------------------------------------------------------*/
/* encodes input (unsigned char) into output (unsigned int),
assumes that lLen is a multiple of 4 */
void _MD5_decode(unsigned int *pout, unsigned char *pin, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
pout[i] = ((unsigned int) pin[j]) | (((unsigned int) pin[j + 1]) << 8) | (((unsigned int) pin[j + 2])
<< 16) | (((unsigned int)
pin[j + 3]) << 24);
}
/*------------------------------------------------------------------*/
BOOL file_exist(char *file_name)
{
int fh;
fh = open(file_name, O_RDONLY);
if (fh < 0)
return FALSE;
close(fh);
return TRUE;
}
/*------------------------------------------------------------------*/
void serialdate2date(double days, int *day, int *month, int *year)
/* convert days since 1.1.1900 to date */
{
int i, j, l, n;
l = (int) days + 68569 + 2415019;
n = (int) ((4 * l) / 146097);
l = l - (int) ((146097 * n + 3) / 4);
i = (int) ((4000 * (l + 1)) / 1461001);
l = l - (int) ((1461 * i) / 4) + 31;
j = (int) ((80 * l) / 2447);
*day = l - (int) ((2447 * j) / 80);
l = (int) (j / 11);
*month = j + 2 - (12 * l);
*year = 100 * (n - 49) + i + l;
}
double date2serialdate(int day, int month, int year)
/* convert date to days since 1.1.1900 */
{
int serialdate;
serialdate = (int) ((1461 * (year + 4800 + (int) ((month - 14) / 12))) / 4) + (int) ((367 * (month - 2
-
12 *
((month -
14) /
12))) / 12) -
(int) ((3 * ((int) ((year + 4900 + (int) ((month - 14) / 12))
/ 100))) / 4) + day - 2415019 - 32075;
return serialdate;
}
/*------------------------------------------------------------------*/
/* Wrapper for setegid. */
int setegroup(char *str)
{
#ifdef OS_UNIX
struct group *gr;
gr = getgrnam(str);
if (gr != NULL)
if (setregid(-1, gr->gr_gid) >= 0 && initgroups(gr->gr_name, gr->gr_gid) >= 0)
return 0;
else {
eprintf("Cannot set effective GID to group \"%s\"\n", gr->gr_name);
eprintf("setgroup: %s\n", strerror(errno));
} else
eprintf("Group \"%s\" not found\n", str);
return -1;
#else
return 0;
#endif
}
/* Wrapper for seteuid. */
int seteuser(char *str)
{
#ifdef OS_UNIX
struct passwd *pw;
pw = getpwnam(str);
if (pw != NULL)
if (setreuid(-1, pw->pw_uid) >= 0) {
return 0;
} else {
eprintf("Cannot set effective UID to user \"%s\"\n", str);
eprintf("setuser: %s\n", strerror(errno));
} else
eprintf("User \"%s\" not found\n", str);
return -1;
#else
return 0;
#endif
}
/* Wrapper for setgid. */
int setgroup(char *str)
{
#ifdef OS_UNIX
struct group *gr;
gr = getgrnam(str);
if (gr != NULL)
if (setgid(gr->gr_gid) >= 0 && initgroups(gr->gr_name, gr->gr_gid) >= 0)
return 0;
else {
eprintf("Cannot set effective GID to group \"%s\"\n", gr->gr_name);
eprintf("setgroup: %s\n", strerror(errno));
} else
eprintf("Group \"%s\" not found\n", str);
return -1;
#else
return 0;
#endif
}
/* Wrapper for setuid. */
int setuser(char *str)
{
#ifdef OS_UNIX
struct passwd *pw;
pw = getpwnam(str);
if (pw != NULL)
if (setuid(pw->pw_uid) >= 0)
return 0;
else {
eprintf("Cannot set effective UID to user \"%s\"\n", str);
eprintf("setuser: %s\n", strerror(errno));
} else
eprintf("User \"%s\" not found\n", str);
return -1;
#else
return 0;
#endif
}
/*-------------------------------------------------------------------*/
int recv_string(int sock, char *buffer, int buffer_size, int millisec)
{
int i, n;
fd_set readfds;
struct timeval timeout;
n = 0;
memset(buffer, 0, buffer_size);
do {
if (millisec > 0) {
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
timeout.tv_sec = millisec / 1000;
timeout.tv_usec = (millisec % 1000) * 1000;
select(FD_SETSIZE, (void *) &readfds, NULL, NULL, (void *) &timeout);
if (!FD_ISSET(sock, &readfds))
break;
}
i = recv(sock, buffer + n, 1, 0);
if (i <= 0)
break;
n++;
if (n >= buffer_size)
break;
} while (buffer[n - 1] && buffer[n - 1] != 10);
return n - 1;
}
/*-------------------------------------------------------------------*/
SESSION_ID *_sid = NULL;
int _n_sid;
int sid_new(LOGBOOK * lbs, const char *user, const char *host, char *sid)
{
double exp;
time_t now;
int i, new_i;
char str[256];
time(&now);
new_i = 0;
if (_sid == NULL) {
_sid = (SESSION_ID *) malloc(sizeof(SESSION_ID));
_n_sid = 1;
new_i = 0;
} else {
exp = 24;
str[0] = 0;
if (lbs == NULL)
getcfg("global", "Login expiration", str, sizeof(str));
else
getcfg(lbs->name, "Login expiration", str, sizeof(str));
if (atof(str) > 0)
exp = atof(str);
if (exp < 24)
exp = 24; /* one day minimum for dangling edit pages */
/* search for expired sid */
for (i = 0; i < _n_sid; i++) {
if (_sid[i].time + exp * 3600 < now) {
new_i = i;
break;
}
}
if (i == _n_sid) {
_sid = (SESSION_ID *) realloc(_sid, sizeof(SESSION_ID) * (_n_sid + 1));
new_i = _n_sid;
_n_sid++;
}
}
strlcpy(_sid[new_i].user_name, user, sizeof(_sid[0].user_name));
strlcpy(_sid[new_i].host_ip, host, sizeof(_sid[0].host_ip));
for (i = 0; i < 4; i++)
sprintf(sid + i * 4, "%04X", rand() % 0x10000);
sid[16] = 0;
strlcpy(_sid[new_i].session_id, sid, sizeof(_sid[0].session_id));
_sid[new_i].time = now;
return 1;
}
/*-------------------------------------------------------------------*/
int sid_check(char *sid, char *user_name)
{
int i;
time_t now;
if (sid == NULL)
return FALSE;
time(&now);
for (i = 0; i < _n_sid; i++) {
if (strcmp(_sid[i].host_ip, (char *) inet_ntoa(rem_addr)) == 0 && strcmp(_sid[i].session_id, sid) == 0) {
strcpy(user_name, _sid[i].user_name);
_sid[i].time = now;
return TRUE;
}
}
return FALSE;
}
/*-------------------------------------------------------------------*/
int sid_remove(char *sid)
{
int i;
if (sid == NULL)
return FALSE;
for (i = 0; i < _n_sid; i++) {
if (strcmp(_sid[i].session_id, sid) == 0) {
memset(&_sid[i], 0, sizeof(SESSION_ID));
return TRUE;
}
}
return FALSE;
}
/*-------------------------------------------------------------------*/
void compose_email_header(LOGBOOK * lbs, char *subject, char *from, char *to, char *url, char *mail_text,
int size, int mail_encoding, int n_attachments, char *multipart_boundary,
int message_id, int reply_id)
{
char buffer[256], charset[256], subject_enc[5000];
char buf[80], str[256];
int i, offset, multipart;
time_t now;
struct tm *ts;
i = 0;
if (mail_encoding & 1)
i++;
if (mail_encoding & 2)
i++;
if (mail_encoding & 4)
i++;
multipart = i > 1;
if (!getcfg("global", "charset", charset, sizeof(charset)))
strcpy(charset, DEFAULT_HTTP_CHARSET);
/* switch locale temporarily back to english to comply with RFC2822 date format */
setlocale(LC_ALL, "C");
time(&now);
ts = localtime(&now);
assert(ts);
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S", ts);
offset = (-(int) my_timezone());
if (ts->tm_isdst)
offset += 3600;
if (is_verbose()) {
sprintf(str, "timezone: %d, offset: %d\n", (int) my_timezone(), (int) offset);
efputs(str);
}
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "Date: %s %+03d%02d\r\n", buf,
(int) (offset / 3600), (int) ((abs((int) offset) / 60) % 60));
getcfg("global", "Language", str, sizeof(str));
if (str[0])
setlocale(LC_ALL, str);
strlcat(mail_text, "To: ", size);
if (getcfg(lbs->name, "Omit Email to", str, sizeof(str)) && atoi(str) == 1)
strlcat(mail_text, "ELOG", size);
else
strlcat(mail_text, to, size);
strlcat(mail_text, "\r\n", size);
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "From: %s\r\n", from);
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "User-Agent: Elog Version %s\r\n",
VERSION);
strlcat(mail_text, "MIME-Version: 1.0\r\n", size);
memset(subject_enc, 0, sizeof(subject_enc));
for (i = 0; i < (int) strlen(subject); i++)
if (subject[i] < 0)
break;
if (i < (int) strlen(subject)) {
/* subject contains local characters, so encode it using charset */
for (i = 0; i < (int) strlen(subject); i += 40) {
strlcpy(buffer, subject + i, sizeof(buffer));
buffer[40] = 0;
strlcat(subject_enc, "=?", sizeof(subject_enc));
strlcat(subject_enc, charset, sizeof(subject_enc));
strlcat(subject_enc, "?B?", sizeof(subject_enc));
base64_encode((unsigned char *) buffer, (unsigned char *) (subject_enc + strlen(subject_enc)),
sizeof(subject_enc) - strlen(subject_enc));
strlcat(subject_enc, "?=", sizeof(subject_enc));
if (strlen(subject + i) < 40)
break;
strlcat(subject_enc, "\r\n ", sizeof(subject_enc)); // another encoded-word
}
} else
strlcpy(subject_enc, subject, sizeof(subject_enc));
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "Subject: %s\r\n", subject_enc);
if (strchr(from, '@')) {
strlcpy(str, strchr(from, '@') + 1, sizeof(str));
if (strchr(str, '>'))
*strchr(str, '>') = 0;
} else
strlcpy(str, "elog.org", sizeof(str));
if (message_id)
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "Message-ID: <%s-%d@%s>\r\n",
lbs->name_enc, message_id, str);
if (reply_id)
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "In-Reply-To: <%s-%d@%s>\r\n",
lbs->name_enc, reply_id, str);
if (url)
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1, "X-Elog-URL: %s\r\n", url);
strlcat(mail_text, "X-Elog-submit-type: web|elog\r\n", size);
if (multipart) {
sprintf(multipart_boundary, "------------%04X%04X%04X", rand(), rand(), rand());
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1,
"MIME-Version: 1.0\r\nContent-Type: multipart/alternative;\r\n boundary=\"%s\"\r\n\r\n",
multipart_boundary);
strlcat(mail_text, "This is a multi-part message in MIME format.\r\n", size);
} else {
if (n_attachments) {
sprintf(multipart_boundary, "------------%04X%04X%04X", rand(), rand(), rand());
snprintf(mail_text + strlen(mail_text), size - strlen(mail_text) - 1,
"MIME-Version: 1.0\r\nContent-Type: multipart/mixed;\r\n boundary=\"%s\"\r\n\r\n",
multipart_boundary);
strlcat(mail_text, "This is a multi-part message in MIME format.\r\n", size);
} else {
if (multipart_boundary)
multipart_boundary[0] = 0;
}
}
}
/*-------------------------------------------------------------------*/
int check_smtp_error(char *str, int expected, char *error, int error_size)
{
if (atoi(str) != expected) {
if (error)
strlcpy(error, str + 4, error_size);
return 0;
}
return 1;
}
/*-------------------------------------------------------------------*/
int sendmail(LOGBOOK * lbs, char *smtp_host, char *from, char *to, char *text, char *error, int error_size)
{
struct sockaddr_in bind_addr;
struct hostent *phe;
int i, n, s, strsize;
char *str;
char list[MAX_N_EMAIL][NAME_LENGTH], buffer[10000], decoded[256];
memset(error, 0, error_size);
if (is_verbose())
eprintf("\n\nEmail from %s to %s, SMTP host %s:\n", from, to, smtp_host);
sprintf(buffer, "Email from %s to ", from);
strlcat(buffer, to, sizeof(buffer));
strlcat(buffer, ", SMTP host ", sizeof(buffer));
strlcat(buffer, smtp_host, sizeof(buffer));
strlcat(buffer, ":\n", sizeof(buffer));
write_logfile(lbs, buffer);
/* create a new socket for connecting to remote server */
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1)
return -1;
/* connect to remote node port 25 */
memset(&bind_addr, 0, sizeof(bind_addr));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons((short) 25);
phe = gethostbyname(smtp_host);
if (phe == NULL) {
if (error)
strlcpy(error, loc("Cannot lookup server name"), error_size);
return -1;
}
memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
if (connect(s, (void *) &bind_addr, sizeof(bind_addr)) < 0) {
closesocket(s);
if (error)
strlcpy(error, loc("Cannot connect to server"), error_size);
return -1;
}
strsize = MAX_CONTENT_LENGTH + 1000;
str = xmalloc(strsize);
recv_string(s, str, strsize, 10000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
/* drain server messages */
do {
str[0] = 0;
recv_string(s, str, strsize, 300);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
} while (str[0]);
if (getcfg(lbs->name, "SMTP username", str, strsize)) {
snprintf(str, strsize - 1, "EHLO %s\r\n", host_name);
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
do {
recv_string(s, str, strsize, 3000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 250, error, error_size))
goto smtp_error;
} while (stristr(str, "250 ") == NULL);
} else {
snprintf(str, strsize - 1, "HELO %s\r\n", host_name);
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 3000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 250, error, error_size))
goto smtp_error;
}
/* optional authentication */
if (getcfg(lbs->name, "SMTP username", str, strsize)) {
snprintf(str, strsize - 1, "AUTH LOGIN\r\n");
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 3000);
if (strchr(str, '\r'))
*strchr(str, '\r') = 0;
if (atoi(str) != 334) {
strcat(str, "\n");
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
} else {
base64_decode(str + 4, decoded);
strcat(decoded, "\n");
if (is_verbose())
efputs(decoded);
write_logfile(lbs, decoded);
}
if (!check_smtp_error(str, 334, error, error_size))
goto smtp_error;
getcfg(lbs->name, "SMTP username", decoded, sizeof(decoded));
base64_encode((unsigned char *) decoded, (unsigned char *) str, strsize);
strcat(str, "\r\n");
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(decoded);
write_logfile(lbs, decoded);
recv_string(s, str, strsize, 3000);
if (strchr(str, '\r'))
*strchr(str, '\r') = 0;
base64_decode(str + 4, decoded);
strcat(decoded, "\n");
if (is_verbose())
efputs(decoded);
write_logfile(lbs, decoded);
if (!check_smtp_error(str, 334, error, error_size))
goto smtp_error;
getcfg(lbs->name, "SMTP password", str, strsize);
strcat(str, "\r\n");
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 3000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 235, error, error_size))
goto smtp_error;
}
snprintf(str, strsize - 1, "MAIL FROM: %s\r\n", from);
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 3000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 250, error, error_size))
goto smtp_error;
/* break recipients into list */
n = strbreak(to, list, MAX_N_EMAIL, ",", FALSE);
for (i = 0; i < n; i++) {
if (list[i] == 0 || strchr(list[i], '@') == NULL)
continue;
snprintf(str, strsize - 1, "RCPT TO: <%s>\r\n", list[i]);
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
/* increased timeout for SMTP servers with long alias lists */
recv_string(s, str, strsize, 30000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 250, error, error_size))
goto smtp_error;
}
snprintf(str, strsize - 1, "DATA\r\n");
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 3000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 354, error, error_size))
goto smtp_error;
/* replace "." at beginning of line by ".." */
strlcpy(str, text, strsize);
strsubst(str, strsize, "\r\n.\r\n", "\r\n..\r\n");
/* add "." to signal end of message */
strlcat(str, ".\r\n", strsize);
/* check if buffer exceeded */
if ((int) strlen(str) == strsize - 1) {
strlcpy(error, loc("Entry size too large for email notification"), error_size);
goto smtp_error;
}
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 10000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 250, error, error_size))
goto smtp_error;
snprintf(str, strsize - 1, "QUIT\r\n");
send(s, str, strlen(str), 0);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
recv_string(s, str, strsize, 3000);
if (is_verbose())
efputs(str);
write_logfile(lbs, str);
if (!check_smtp_error(str, 221, error, error_size))
goto smtp_error;
closesocket(s);
xfree(str);
return 1;
smtp_error:
closesocket(s);
xfree(str);
return -1;
}
/*------------------------------------------------------------------*/
int elog_connect(char *host, int port)
{
int status, sock;
struct hostent *phe;
struct sockaddr_in bind_addr;
/* create socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("cannot create socket");
return -1;
}
/* 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);
if (phe == NULL) {
perror("cannot get 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)
return -1;
return sock;
}
/*------------------------------------------------------------------*/
#ifdef HAVE_SSL
int ssl_connect(int sock, SSL ** ssl_con)
{
SSL_METHOD *meth;
SSL_CTX *ctx;
SSL_library_init();
SSL_load_error_strings();
meth = (SSL_METHOD *) SSLv23_method();
ctx = SSL_CTX_new(meth);
*ssl_con = SSL_new(ctx);
SSL_set_fd(*ssl_con, sock);
if (SSL_connect(*ssl_con) <= 0)
return -1;
return 0;
}
#endif
/*-------------------------------------------------------------------*/
void split_url(const char *url, char *host, int *port, char *subdir, char *param)
{
const char *p;
char str[256];
if (host)
host[0] = 0;
if (port)
*port = 80;
if (subdir)
subdir[0] = 0;
if (param)
param[0] = 0;
p = url;
if (strncmp(url, "http://", 7) == 0)
p += 7;
if (strncmp(url, "https://", 8) == 0)
p += 8;
strncpy(str, p, sizeof(str));
if (strchr(str, '/')) {
if (subdir)
strncpy(subdir, strchr(str, '/'), 256);
*strchr(str, '/') = 0;
}
if (strchr(str, '?')) {
if (subdir)
strncpy(subdir, strchr(str, '?'), 256);
*strchr(str, '?') = 0;
}
if (strchr(str, ':')) {
if (port)
*port = atoi(strchr(str, ':') + 1);
*strchr(str, ':') = 0;
}
if (host)
strcpy(host, str);
if (subdir) {
if (strchr(subdir, '?')) {
strncpy(param, strchr(subdir, '?'), 256);
*strchr(subdir, '?') = 0;
}
if (subdir[0] == 0)
strcpy(subdir, "/");
}
}
/*-------------------------------------------------------------------*/
int retrieve_url(LOGBOOK * lbs, const char *url, int ssl, char **buffer)
{
char str[1000], unm[256], upwd[256], host[256], subdir[256], param[256];
int port, bufsize;
int i, n;
fd_set readfds;
struct timeval timeout;
#ifdef HAVE_SSL
static SSL *ssl_con;
#endif
static int sock, last_port;
static char last_host[256];
*buffer = NULL;
split_url(url, host, &port, subdir, param);
if (sock && (strcmp(host, last_host) != 0 || port != last_port)) {
#ifdef HAVE_SSL
if (ssl) {
SSL_shutdown(ssl_con);
SSL_free(ssl_con);
}
#endif
closesocket(sock);
sock = 0;
}
if (sock) { // keep-alive does not yet work, requires evaluation of Content-Length !!!
#ifdef HAVE_SSL
if (ssl) {
SSL_shutdown(ssl_con);
SSL_free(ssl_con);
}
#endif
closesocket(sock);
sock = 0;
}
/* create a new socket for connecting to remote server */
if (!sock) {
sock = elog_connect(host, port);
if (sock == -1)
return -1;
#ifdef HAVE_SSL
if (ssl)
if (ssl_connect(sock, &ssl_con) < 0) {
printf("Error initiating SSL connection\n");
return -1;
}
#endif
}
last_port = port;
strcpy(last_host, host);
/* compose GET request, avoid chunked data in HTTP/1.1 protocol */
sprintf(str, "GET %s%s HTTP/1.0\r\nConnection: Close\r\n", subdir, param);
/* add local username/password */
if (isparam("unm")) {
strlcpy(unm, getparam("unm"), sizeof(unm));
if (isparam("upwd"))
strlcpy(upwd, getparam("upwd"), sizeof(upwd));
else
get_user_line(lbs, getparam("unm"), upwd, NULL, NULL, NULL, NULL, NULL);
sprintf(str + strlen(str), "Cookie: unm=%s; upwd=%s\r\n", unm, upwd);
}
/* add host (RFC2616, Sec. 14) */
sprintf(str + strlen(str), "Host: %s:%d\r\n", host, port);
/* add keepalive */
//sprintf(str + strlen(str), "Keep-Alive: 600\r\n");
//sprintf(str + strlen(str), "Connection: keep-alive\r\n");
strcat(str, "\r\n");
#ifdef HAVE_SSL
if (ssl)
SSL_write(ssl_con, str, strlen(str));
else
#endif
send(sock, str, strlen(str), 0);
bufsize = TEXT_SIZE + 1000;
*buffer = xmalloc(bufsize);
memset(*buffer, 0, bufsize);
n = 0;
do {
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
timeout.tv_sec = 30; /* 30 sec. timeout */
timeout.tv_usec = 0;
select(FD_SETSIZE, (void *) &readfds, NULL, NULL, (void *) &timeout);
if (!FD_ISSET(sock, &readfds)) {
closesocket(sock);
sock = 0;
xfree(*buffer);
*buffer = NULL;
return -1;
}
#ifdef HAVE_SSL
if (ssl)
i = SSL_read(ssl_con, *buffer + n, bufsize - n);
else
#endif
i = recv(sock, *buffer + n, bufsize - n, 0);
if (i <= 0)
break;
n += i;
if (n >= bufsize) {
/* increase buffer size */
bufsize += 10000;
*buffer = (char *) xrealloc(*buffer, bufsize);
if (*buffer == NULL) {
closesocket(sock);
return -1;
}
}
} while (1);
return n;
}
/*-------------------------------------------------------------------*/
int ss_daemon_init()
{
#ifdef OS_UNIX
/* only implemented for UNIX */
int i, fd, pid;
if ((pid = fork()) < 0)
return FAILURE;
else if (pid != 0)
_exit(EXIT_SUCCESS); /* parent finished, exit without atexit hook */
/* child continues here */
/* try and use up stdin, stdout and stderr, so other
routines writing to stdout etc won't cause havoc. Copied from smbd */
for (i = 0; i < 3; i++) {
close(i);
fd = open("/dev/null", O_RDWR, 0);
if (fd < 0)
fd = open("/dev/null", O_WRONLY, 0);
if (fd < 0) {
eprintf("Can't open /dev/null");
return FAILURE;
}
if (fd != i) {
eprintf("Did not get file descriptor");
return FAILURE;
}
}
setsid(); /* become session leader */
chdir("/"); /* change working direcotry (not on NFS!) */
umask(0); /* clear our file mode creation mask */
#endif
return SUCCESS;
}
/*------------------------------------------------------------------*/
/* Parameter extraction from configuration file similar to win.ini */
typedef struct {
char *param;
char *uparam;
char *value;
} CONFIG_PARAM;
typedef struct {
char *section_name;
int n_params;
CONFIG_PARAM *config_param;
} LB_CONFIG;
LB_CONFIG *lb_config = NULL;
int n_lb_config = 0;
char _topgroup[256];
char _condition[256];
time_t cfgfile_mtime = 0;
/*-------------------------------------------------------------------*/
void check_config_file(BOOL force)
{
struct stat cfg_stat;
if (force) {
parse_config_file(config_file);
return;
}
/* force re-read configuration file if changed */
if (stat(config_file, &cfg_stat) == 0) {
if (cfgfile_mtime < cfg_stat.st_mtime) {
cfgfile_mtime = cfg_stat.st_mtime;
parse_config_file(config_file);
}
} else
eprintf("Cannot stat() config file \"%s\": %s\n", config_file, strerror(errno));
}
/*-------------------------------------------------------------------*/
void setcfg_topgroup(char *topgroup)
{
strcpy(_topgroup, topgroup);
}
char *getcfg_topgroup()
{
if (_topgroup[0])
return _topgroup;
return NULL;
}
/*------------------------------------------------------------------*/
int is_logbook(char *logbook)
{
char str[256];
if (strieq(logbook, "global"))
return 0;
/* check for 'global group' or 'global_xxx' */
strlcpy(str, logbook, sizeof(str));
str[7] = 0;
return !strieq(str, "global ");
}
/*-------------------------------------------------------------------*/
void set_condition(char *c)
{
strlcpy(_condition, c, sizeof(_condition));
}
/*-------------------------------------------------------------------*/
void evaluate_conditions(LOGBOOK * lbs, char attrib[MAX_N_ATTR][NAME_LENGTH])
{
char condition[256], str[256];
int index, i;
condition[0] = 0;
set_condition("");
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);
scan_attributes(lbs->name);
}
}
}
}
}
/*-------------------------------------------------------------------*/
BOOL match_param(char *str, char *param, int conditional_only)
{
int ncl, npl, nand, i, j, k;
char *p, pcond[256], clist[10][NAME_LENGTH], plist[10][NAME_LENGTH], alist[10][NAME_LENGTH];
if (conditional_only && str[0] != '{')
return FALSE;
if (!_condition[0] || str[0] != '{')
return (stricmp(str, param) == 0);
p = str;
if (strchr(p, '}'))
p = strchr(p, '}') + 1;
while (*p == ' ')
p++;
strlcpy(pcond, str, sizeof(pcond));
if (strchr(pcond, '}'))
*strchr(pcond, '}') = 0;
if (strchr(pcond, '{'))
*strchr(pcond, '{') = ' ';
npl = strbreak(pcond, plist, 10, ",", FALSE);
ncl = strbreak(_condition, clist, 10, ",", FALSE);
for (i = 0; i < ncl; i++)
for (j = 0; j < npl; j++)
if (stricmp(clist[i], plist[j]) == 0) {
/* condition matches */
return stricmp(p, param) == 0;
}
/* check and'ed conditions */
for (i = 0; i < npl; i++)
if (strchr(plist[i], '&')) {
nand = strbreak(plist[i], alist, 10, "&", FALSE);
for (j = 0; j < nand; j++) {
for (k = 0; k < ncl; k++)
if (stricmp(clist[k], alist[j]) == 0)
break;
if (k == ncl)
return FALSE;
}
if (j == nand)
return stricmp(p, param) == 0;
}
return 0;
}
/*-------------------------------------------------------------------*/
int param_compare(const void *p1, const void *p2)
{
return stricmp(((CONFIG_PARAM *) p1)->uparam, ((CONFIG_PARAM *) p2)->uparam);
}
/*------------------------------------------------------------------*/
void free_config()
{
int i, j;
for (i = 0; i < n_lb_config; i++) {
for (j = 0; j < lb_config[i].n_params; j++) {
xfree(lb_config[i].config_param[j].param);
xfree(lb_config[i].config_param[j].uparam);
xfree(lb_config[i].config_param[j].value);
}
if (lb_config[i].config_param)
xfree(lb_config[i].config_param);
xfree(lb_config[i].section_name);
}
xfree(lb_config);
lb_config = NULL;
n_lb_config = 0;
}
/*------------------------------------------------------------------*/
int parse_config_file(char *file_name)
/* parse whole config file and store options in sorted list */
{
char *str, *buffer, *p, *pstr;
int index, i, j, fh, length;
str = xmalloc(20000);
/* open configuration file */
fh = open(file_name, O_RDONLY | O_BINARY);
if (fh < 0)
return 0;
length = lseek(fh, 0, SEEK_END);
lseek(fh, 0, SEEK_SET);
buffer = xmalloc(length + 1);
read(fh, buffer, length);
buffer[length] = 0;
close(fh);
/* release previously allocated memory */
if (lb_config)
free_config();
/* search group */
p = buffer;
index = 0;
do {
if (*p == '#' || *p == ';') {
/* skip comment */
while (*p && *p != '\n' && *p != '\r')
p++;
} else if (*p == '[') {
p++;
pstr = str;
while (*p && *p != ']' && *p != '\n' && *p != '\r' && pstr - str < 10000)
*pstr++ = *p++;
*pstr = 0;
/* allocate new group */
if (!lb_config)
lb_config = xmalloc(sizeof(LB_CONFIG));
else
lb_config = xrealloc(lb_config, sizeof(LB_CONFIG) * (n_lb_config + 1));
lb_config[n_lb_config].section_name = xmalloc(strlen(str) + 1);
lb_config[n_lb_config].n_params = 0;
lb_config[n_lb_config].config_param = NULL;
strcpy(lb_config[n_lb_config].section_name, str);
/* enumerate parameters */
i = 0;
p = strchr(p, '\n');
if (p)
p++;
while (p && *p && *p != '[') {
pstr = str;
while (*p && *p != '=' && *p != '\n' && *p != '\r' && pstr - str < 10000)
*pstr++ = *p++;
*pstr-- = 0;
while (pstr > str && (*pstr == ' ' || *pstr == '\t' || *pstr == '='))
*pstr-- = 0;
if (*p == '=') {
if (lb_config[n_lb_config].n_params == 0)
lb_config[n_lb_config].config_param = xmalloc(sizeof(CONFIG_PARAM));
else
lb_config[n_lb_config].config_param = xrealloc(lb_config[n_lb_config].config_param,
sizeof(CONFIG_PARAM) *
(lb_config[n_lb_config].n_params + 1));
lb_config[n_lb_config].config_param[i].param = xmalloc(strlen(str) + 1);
lb_config[n_lb_config].config_param[i].uparam = xmalloc(strlen(str) + 1);
strcpy(lb_config[n_lb_config].config_param[i].param, str);
for (j = 0; j < (int) strlen(str); j++)
lb_config[n_lb_config].config_param[i].uparam[j] = toupper(str[j]);
lb_config[n_lb_config].config_param[i].uparam[j] = 0;
p++;
while (*p == ' ' || *p == '\t')
p++;
pstr = str;
while (*p && *p != '\n' && *p != '\r' && pstr - str < 10000)
*pstr++ = *p++;
*pstr-- = 0;
while (*pstr == ' ' || *pstr == '\t')
*pstr-- = 0;
lb_config[n_lb_config].config_param[i].value = xmalloc(strlen(str) + 1);
strcpy(lb_config[n_lb_config].config_param[i].value, str);
i++;
lb_config[n_lb_config].n_params = i;
}
/* search for next line beginning */
while (*p && *p != '\r' && *p != '\n')
p++;
while (*p && (*p == '\r' || *p == '\n'))
p++;
}
/* sort parameter */
// outcommented: not needed, might screw up group ordering
//qsort(lb_config[n_lb_config].config_param, lb_config[n_lb_config].n_params, sizeof(CONFIG_PARAM),
// param_compare);
n_lb_config++;
index++;
}
/* search for next line beginning */
while (*p && *p != '\r' && *p != '\n' && *p != '[')
p++;
while (*p && (*p == '\r' || *p == '\n'))
p++;
} while (*p);
xfree(str);
xfree(buffer);
return 0;
}
/*-------------------------------------------------------------------*/
int getcfg_simple(char *group, char *param, char *value, int vsize, int conditional)
{
int i, j, status;
char uparam[256];
if (strlen(param) >= sizeof(uparam))
return 0;
for (i = 0; i < (int) strlen(param); i++)
uparam[i] = toupper(param[i]);
uparam[i] = 0;
value[0] = 0;
for (i = 0; i < n_lb_config; i++)
if (strieq(lb_config[i].section_name, group))
break;
if (i == n_lb_config)
return 0;
for (j = 0; j < lb_config[i].n_params; j++)
if (match_param(lb_config[i].config_param[j].uparam, uparam, conditional)) {
status = strchr(lb_config[i].config_param[j].uparam, '{') ? 2 : 1;
strlcpy(value, lb_config[i].config_param[j].value, vsize);
return status;
}
return 0;
}
/*-------------------------------------------------------------------*/
int enumgrp(int index, char *group)
{
if (index < n_lb_config) {
strcpy(group, lb_config[index].section_name);
return 1;
}
return 0;
}
/*-------------------------------------------------------------------*/
int getcfg(char *group, char *param, char *value, int vsize)
/*
Read parameter from configuration file.
- if group == [global] and top group exists, read
from [global ]
- if parameter not in [global ], read from [global]
- if group is logbook, read from logbook section
- if parameter not in [], read from [global ]
or [global]
*/
{
char str[256];
int status;
/* if group is [global] and top group exists, read from there */
if (strieq(group, "global") && getcfg_topgroup()) {
sprintf(str, "global %s", getcfg_topgroup());
status = getcfg(str, param, value, vsize);
if (status)
return status;
}
/* first check if parameter is under condition */
if (_condition[0]) {
status = getcfg_simple(group, param, value, vsize, TRUE);
if (status)
return status;
}
status = getcfg_simple(group, param, value, vsize, FALSE);
if (status)
return status;
/* if parameter not found in logbook, look in [global] section */
if (!group || is_logbook(group))
return getcfg("global", param, value, vsize);
return 0;
}
/*-------------------------------------------------------------------*/
char *find_param(char *buf, char *group, char *param)
{
char *str, *p, *pstr, *pstart;
/* search group */
str = xmalloc(10000);
p = buf;
do {
if (*p == '[') {
p++;
pstr = str;
while (*p && *p != ']' && *p != '\n')
*pstr++ = *p++;
*pstr = 0;
if (strieq(str, group)) {
/* search parameter */
p = strchr(p, '\n');
if (p)
p++;
while (p && *p && *p != '[') {
pstr = str;
pstart = p;
while (*p && *p != '=' && *p != '\n')
*pstr++ = *p++;
*pstr-- = 0;
while (pstr > str && (*pstr == ' ' || *pstr == '=' || *pstr == '\t'))
*pstr-- = 0;
if (match_param(str, param, FALSE)) {
xfree(str);
return pstart;
}
if (p)
p = strchr(p, '\n');
if (p)
p++;
}
}
}
if (p)
p = strchr(p, '\n');
if (p)
p++;
} while (p);
xfree(str);
/* now search if in [global] section */
if (!strieq(group, "global"))
return find_param(buf, "global", param);
return NULL;
}
/*-------------------------------------------------------------------*/
int is_group(char *group)
{
int i;
for (i = 0; i < n_lb_config; i++)
if (strieq(group, lb_config[i].section_name))
return 1;
return 0;
}
/*------------------------------------------------------------------*/
int enumcfg(char *group, char *param, int psize, char *value, int vsize, int index)
{
int i;
for (i = 0; i < n_lb_config; i++)
if (strieq(group, lb_config[i].section_name)) {
if (index < lb_config[i].n_params) {
strlcpy(param, lb_config[i].config_param[index].param, psize);
strlcpy(value, lb_config[i].config_param[index].value, vsize);
return 1;
}
return 0;
}
return 0;
}
/*-------------------------------------------------------------------*/
int exist_top_group()
{
int i;
char str[256];
for (i = 0;; i++) {
if (!enumcfg("global", str, sizeof(str), NULL, 0, i))
break;
str[9] = 0;
if (strieq(str, "top group"))
return 1;
}
return 0;
}
/*-------------------------------------------------------------------*/
char *_locbuffer = NULL;
char **_porig, **_ptrans;
time_t _locfile_mtime = 0;
/* check if language file changed and if so reload it */
int check_language()
{
char language[256], file_name[256], *p;
int fh, length, n;
struct stat cfg_stat;
getcfg("global", "Language", language, sizeof(language));
/* set locale for strftime */
if (language[0])
setlocale(LC_ALL, language);
else
setlocale(LC_ALL, "english");
/* force re-read configuration file if changed */
strlcpy(file_name, resource_dir, sizeof(file_name));
strlcat(file_name, "resources", sizeof(file_name));
strlcat(file_name, DIR_SEPARATOR_STR, sizeof(file_name));
strlcat(file_name, "eloglang.", sizeof(file_name));
strlcat(file_name, language, sizeof(file_name));
if (stat(file_name, &cfg_stat) == 0) {
if (_locfile_mtime != cfg_stat.st_mtime) {
_locfile_mtime = cfg_stat.st_mtime;
if (_locbuffer) {
xfree(_locbuffer);
_locbuffer = NULL;
}
}
}
if (strieq(language, "english") || language[0] == 0) {
if (_locbuffer) {
xfree(_locbuffer);
_locbuffer = NULL;
}
} else {
if (_locbuffer == NULL) {
fh = open(file_name, O_RDONLY | O_BINARY);
if (fh < 0)
return -1;
length = lseek(fh, 0, SEEK_END);
lseek(fh, 0, SEEK_SET);
_locbuffer = xmalloc(length + 1);
read(fh, _locbuffer, length);
_locbuffer[length] = 0;
close(fh);
/* scan lines, setup orig-translated pointers */
p = _locbuffer;
n = 0;
do {
while (*p && (*p == '\r' || *p == '\n'))
p++;
if (*p && (*p == ';' || *p == '#' || *p == ' ' || *p == '\t')) {
while (*p && *p != '\n' && *p != '\r')
p++;
continue;
}
if (n == 0) {
_porig = xmalloc(sizeof(char *) * 2);
_ptrans = xmalloc(sizeof(char *) * 2);
} else {
_porig = xrealloc(_porig, sizeof(char *) * (n + 2));
_ptrans = xrealloc(_ptrans, sizeof(char *) * (n + 2));
}
_porig[n] = p;
while (*p && (*p != '=' && *p != '\r' && *p != '\n'))
p++;
if (*p && *p != '=')
continue;
_ptrans[n] = p + 1;
while (*_ptrans[n] == ' ' || *_ptrans[n] == '\t')
_ptrans[n]++;
/* remove '=' and surrounding blanks */
while (*p == '=' || *p == ' ' || *p == '\t')
*p-- = 0;
p = _ptrans[n];
while (*p && *p != '\n' && *p != '\r')
p++;
if (p)
*p++ = 0;
n++;
} while (p && *p);
_porig[n] = NULL;
_ptrans[n] = NULL;
}
}
return 0;
}
/*-------------------------------------------------------------------*/
/* localization support */
char *loc(char *orig)
{
int n;
char language[256];
static char result[256];
if (!_locbuffer)
return orig;
/* search string and return translation */
for (n = 0; _porig[n]; n++)
if (strcmp(orig, _porig[n]) == 0) {
if (*_ptrans[n])
return _ptrans[n];
return orig;
}
/* special case: "Change %s" */
if (strstr(orig, "Change ") && strcmp(orig, "Change %s") != 0) {
sprintf(result, loc("Change %s"), orig + 7);
return result;
}
/* special case: some intrinsic commands */
if (strstr(orig, "GetPwdFile")) {
strcpy(result, orig);
return result;
}
getcfg("global", "Language", language, sizeof(language));
eprintf("Language error: string \"%s\" not found for language \"%s\"\n", orig, language);
return orig;
}
/*-------------------------------------------------------------------*/
/* translate back from localized string to english */
char *unloc(char *orig)
{
int n;
if (!_locbuffer)
return orig;
/* search string and return translation */
for (n = 0; _ptrans[n]; n++)
if (strcmp(orig, _ptrans[n]) == 0) {
if (*_porig[n])
return _porig[n];
return orig;
}
eprintf("Language error: string \"%s\" not found in English\n", orig);
return orig;
}
/*-------------------------------------------------------------------*/
char *month_name(int m)
/* return name of month in current locale, m=0..11 */
{
struct tm ts;
static char name[32];
memset(&ts, 0, sizeof(ts));
ts.tm_mon = m;
ts.tm_mday = 15;
ts.tm_year = 2000;
mktime(&ts);
strftime(name, sizeof(name), "%B", &ts);
return name;
}
/*-------------------------------------------------------------------*/
time_t date_to_ltime(char *date)
{
struct tm tms;
int i, date_zone, local_zone;
time_t ltime;
memset(&tms, 0, sizeof(struct tm));
if (strlen(date) > 25) {
/* RFC2822 compliant date */
for (i = 0; i < 12; i++)
if (strncmp(date + 8, mname[i], 3) == 0)
break;
tms.tm_mon = i;
tms.tm_mday = atoi(date + 5);
tms.tm_hour = atoi(date + 17);
tms.tm_min = atoi(date + 20);
tms.tm_sec = atoi(date + 23);
tms.tm_year = atoi(date + 12) - 1900;
tms.tm_isdst = -1;
if (tms.tm_year < 90)
tms.tm_year += 100;
ltime = mktime(&tms);
/* correct for difference between local time zone (used by mktime) and time zone of date */
date_zone = atoi(date + 26);
/* correct for incorrect date_zone */
if (date_zone > 2400 || date_zone < -2400)
date_zone = 0;
date_zone = (abs(date_zone) % 100) * 60 + (date_zone) / 100 * 3600;
local_zone = my_timezone();
if (tms.tm_isdst)
local_zone -= 3600;
ltime = ltime - local_zone - date_zone;
} else {
/* ctime() complient date */
for (i = 0; i < 12; i++)
if (strncmp(date + 4, mname[i], 3) == 0)
break;
tms.tm_mon = i;
tms.tm_mday = atoi(date + 8);
tms.tm_hour = atoi(date + 11);
tms.tm_min = atoi(date + 14);
tms.tm_sec = atoi(date + 17);
tms.tm_year = atoi(date + 20) - 1900;
tms.tm_isdst = -1;
if (tms.tm_year < 90)
tms.tm_year += 100;
ltime = mktime(&tms);
}
return ltime;
}
/*-------------------------------------------------------------------*/
void check_config()
{
check_config_file(FALSE);
check_language();
}
/*-------------------------------------------------------------------*/
void retrieve_domain(char *ret, int size)
{
char smtp_host[80];
strlcpy(ret, "tmp.org", size);
if (getcfg("global", "SMTP host", smtp_host, sizeof(smtp_host))) {
if (strchr(smtp_host, '.'))
strlcpy(ret, strchr(smtp_host, '.') + 1, size);
}
}
/*-------------------------------------------------------------------*/
void retrieve_email_from(LOGBOOK * lbs, char *ret, char *ret_name, char attrib[MAX_N_ATTR][NAME_LENGTH])
{
char email_from[256], email_from_name[256], str[256], *p, login_name[256],
slist[MAX_N_ATTR + 10][NAME_LENGTH], svalue[MAX_N_ATTR + 10][NAME_LENGTH],
full_name[256], user_email[256];
int i;
if (getcfg(lbs->name, "Use Email from", str, sizeof(str))) {
if (str[0] != '<') {
strlcpy(email_from, "<", sizeof(email_from));
strlcat(email_from, str, sizeof(email_from));
strlcat(email_from, ">", sizeof(email_from));
} else
strlcpy(email_from, str, sizeof(email_from));
strlcpy(email_from_name, str, sizeof(email_from));
} else if (isparam("unm")) {
get_user_line(lbs, getparam("unm"), NULL, full_name, user_email, NULL, NULL, NULL);
strlcpy(email_from_name, full_name, sizeof(email_from_name));
strlcat(email_from_name, " <", sizeof(email_from_name));
strlcat(email_from_name, user_email, sizeof(email_from_name));
strlcat(email_from_name, ">", sizeof(email_from_name));
strlcpy(email_from, "<", sizeof(email_from));
strlcat(email_from, user_email, sizeof(email_from));
strlcat(email_from, ">", sizeof(email_from));
} else if (getcfg(lbs->name, "Default Email from", str, sizeof(str))) {
if (str[0] != '<') {
strlcpy(email_from, "<", sizeof(email_from));
strlcat(email_from, str, sizeof(email_from));
strlcat(email_from, ">", sizeof(email_from));
} else
strlcpy(email_from, str, sizeof(email_from));
strlcpy(email_from_name, str, sizeof(email_from));
} else {
sprintf(email_from_name, "ELog ", host_name);
sprintf(email_from, "", host_name);
}
if (attrib) {
i = build_subst_list(lbs, slist, svalue, attrib, TRUE);
strsubst_list(email_from_name, sizeof(email_from_name), slist, svalue, i);
strsubst_list(email_from, sizeof(email_from), slist, svalue, i);
/* remove possible 'mailto:' */
if ((p = strstr(email_from_name, "mailto:")) != NULL)
memmove(p, p + 7, strlen(p + 7) + 1);
if ((p = strstr(email_from, "mailto:")) != NULL)
memmove(p, p + 7, strlen(p + 7) + 1);
}
/* if nothing available, figure out email from an administrator */
if (strchr(email_from, '@') == NULL) {
for (i = 0;; i++) {
if (!enum_user_line(lbs, i, login_name, sizeof(login_name)))
break;
get_user_line(lbs, login_name, NULL, NULL, email_from, NULL, NULL, NULL);
sprintf(email_from_name, "%s <%s>", login_name, email_from);
if (is_admin_user(lbs->name, login_name) && strchr(email_from, '@'))
break;
}
}
if (ret)
strcpy(ret, email_from);
if (ret_name)
strcpy(ret_name, email_from_name);
}
/*------------------------------------------------------------------*/
void el_decode(char *message, char *key, char *result, int size)
{
char *pc, *ph;
int i;
if (result == NULL)
return;
*result = 0;
ph = strstr(message, "========================================");
if (ph == NULL)
return;
do {
if (ph[40] == '\r' || ph[40] == '\n')
break;
ph = strstr(ph + 40, "========================================");
if (ph == NULL)
return;
} while (1);
/* go through all lines */
for (pc = message; pc < ph;) {
if (strncmp(pc, key, strlen(key)) == 0) {
pc += strlen(key);
for (i = 0; *pc != '\n' && *pc != '\r' && i < size - 1; i++)
result[i] = *pc++;
result[i] = 0;
return;
}
pc = strchr(pc, '\n');
if (pc == NULL)
return;
while (*pc && (*pc == '\n' || *pc == '\r'))
pc++;
}
}
/*------------------------------------------------------------------*/
void el_decode_int(char *message, char *key, char *result, int size)
{
char str[80];
if (result == NULL)
return;
*result = 0;
el_decode(message, key, str, sizeof(str));
if (str[0])
sprintf(str, "%d", atoi(str));
strlcpy(result, str, size);
}
/*------------------------------------------------------------------*/
void el_decode_intlist(char *message, char *key, char *result, int size)
{
int i;
if (result == NULL)
return;
*result = 0;
el_decode(message, key, result, size);
/* remove any non allowed characters */
for (i = 0; i < size && i < (int) strlen(result); i++)
if (!isdigit(result[i]) && result[i] != ' ' && result[i] != ',')
result[i] = ' ';
}
/*------------------------------------------------------------------*/
void el_enum_attr(char *message, int n, char *attr_name, char *attr_value)
{
char *p, str[NAME_LENGTH], tmp[NAME_LENGTH];
int i;
p = message;
for (i = 0; i <= n; i++) {
strlcpy(str, p, sizeof(str));
if (strchr(str, '\n'))
*strchr(str, '\n') = 0;
if (strchr(str, '\r'))
*strchr(str, '\r') = 0;
if (strcmp(str, "========================================") == 0)
break;
p = strchr(p, '\n');
if (!p) {
str[0] = 0; /* not a valid line */
break;
}
while (*p == '\n' || *p == '\r')
p++;
if (strchr(str, ':')) {
strcpy(tmp, str);
*strchr(tmp, ':') = 0;
if (strieq(tmp, "$@MID@$") || strieq(tmp, "Date") || strieq(tmp, "Attachment") || strieq(tmp,
"Reply To")
|| strieq(tmp, "In Reply To") || strieq(tmp, "Encoding") || strieq(tmp, "Locked by"))
i--;
}
}
attr_name[0] = 0;
attr_value[0] = 0;
if (strchr(str, ':')) {
strlcpy(attr_name, str, NAME_LENGTH);
*strchr(attr_name, ':') = 0;
strlcpy(attr_value, strchr(str, ':') + 2, NAME_LENGTH);
}
}
/*------------------------------------------------------------------*/
/* Simplified copy of fnmatch() for Cygwin where fnmatch is not defined */
#define EOS '\0'
int fnmatch1(const char *pattern, const char *string)
{
const char *stringstart;
char c, test;
for (stringstart = string;;)
switch (c = *pattern++) {
case EOS:
return (*string == EOS ? 0 : 1);
case '?':
if (*string == EOS)
return (1);
++string;
break;
case '*':
c = *pattern;
/* Collapse multiple stars. */
while (c == '*')
c = *++pattern;
/* Optimize for pattern with * at end or before /. */
if (c == EOS)
return (0);
/* General case, use recursion. */
while ((test = *string) != EOS) {
if (!fnmatch1(pattern, string))
return (0);
++string;
}
return (1);
/* FALLTHROUGH */
default:
if (c != *string)
return (1);
string++;
break;
}
}
/*------------------------------------------------------------------*/
int ss_file_find(char *path, char *pattern, char **plist)
/********************************************************************
Routine: ss_file_find
Purpose: Return list of files matching 'pattern' from the 'path' location
Input:
char *path Name of a file in file system to check
char *pattern pattern string (wildcard allowed)
Output:
char **plist pointer to the file list
Function value:
int Number of files matching request
\********************************************************************/
{
#ifdef OS_UNIX
DIR *dir_pointer;
struct dirent *dp;
int i;
if ((dir_pointer = opendir(path)) == NULL)
return 0;
*plist = (char *) xmalloc(MAX_PATH_LENGTH);
i = 0;
for (dp = readdir(dir_pointer); dp != NULL; dp = readdir(dir_pointer)) {
if (fnmatch1(pattern, dp->d_name) == 0) {
*plist = (char *) xrealloc(*plist, (i + 1) * MAX_PATH_LENGTH);
strncpy(*plist + (i * MAX_PATH_LENGTH), dp->d_name, strlen(dp->d_name));
*(*plist + (i * MAX_PATH_LENGTH) + strlen(dp->d_name)) = '\0';
i++;
}
}
closedir(dir_pointer);
return i;
#endif
#ifdef OS_WINNT
HANDLE pffile;
LPWIN32_FIND_DATA lpfdata;
char str[255];
int i, first;
strlcpy(str, path, sizeof(str));
strlcat(str, "\\", sizeof(str));
strlcat(str, pattern, sizeof(str));
first = 1;
i = 0;
lpfdata = xmalloc(sizeof(WIN32_FIND_DATA));
*plist = (char *) xmalloc(MAX_PATH_LENGTH);
pffile = FindFirstFile(str, lpfdata);
if (pffile == INVALID_HANDLE_VALUE)
return 0;
first = 0;
*plist = (char *) xrealloc(*plist, (i + 1) * MAX_PATH_LENGTH);
strncpy(*plist + (i * MAX_PATH_LENGTH), lpfdata->cFileName, strlen(lpfdata->cFileName));
*(*plist + (i * MAX_PATH_LENGTH) + strlen(lpfdata->cFileName)) = '\0';
i++;
while (FindNextFile(pffile, lpfdata)) {
*plist = (char *) xrealloc(*plist, (i + 1) * MAX_PATH_LENGTH);
strncpy(*plist + (i * MAX_PATH_LENGTH), lpfdata->cFileName, strlen(lpfdata->cFileName));
*(*plist + (i * MAX_PATH_LENGTH) + strlen(lpfdata->cFileName)) = '\0';
i++;
}
xfree(lpfdata);
return i;
#endif
}
/*------------------------------------------------------------------*/
int eli_compare(const void *e1, const void *e2)
{
if (((EL_INDEX *) e1)->file_time < ((EL_INDEX *) e2)->file_time)
return -1;
if (((EL_INDEX *) e1)->file_time >= ((EL_INDEX *) e2)->file_time)
return 1;
return 0;
}
/*------------------------------------------------------------------*/
int el_build_index(LOGBOOK * lbs, BOOL rebuild)
/* scan all ??????a.log files and build an index table in eli[] */
{
char *file_list, str[256], error_str[256], date[256], dir[256], file_name[MAX_PATH_LENGTH], *buffer, *p,
*pn, in_reply_to[80];
int index, n, length;
int i, fh, len;
unsigned char digest[16];
if (rebuild) {
xfree(lbs->el_index);
xfree(lbs->n_el_index);
}
lbs->n_el_index = xmalloc(sizeof(int));
*lbs->n_el_index = 0;
lbs->el_index = xmalloc(0);
/* get data directory */
strcpy(dir, lbs->data_dir);
if (is_verbose() > 1) {
/* show MD5 from config file */
load_config_section(lbs->name, &buffer, error_str);
if (error_str[0])
eprintf(error_str);
else {
remove_crlf(buffer);
MD5_checksum(buffer, strlen(buffer), digest);
eprintf("\n\nConfig [%s], MD5=", lbs->name);
for (i = 0; i < 16; i++)
eprintf("%02X", digest[i]);
eprintf("\n\n");
}
if (buffer)
xfree(buffer);
}
file_list = NULL;
n = ss_file_find(dir, "??????a.log", &file_list);
if (n == 0) {
if (file_list)
xfree(file_list);
file_list = NULL;
n = ss_file_find(dir, "??????.log", &file_list);
if (n > 0)
return EL_UPGRADE;
return EL_EMPTY;
}
if (is_verbose() > 1)
eprintf("Entries:\n");
/* go through all files */
for (index = 0; index < n; index++) {
strlcpy(file_name, dir, sizeof(file_name));
strlcat(file_name, file_list + index * MAX_PATH_LENGTH, sizeof(file_name));
fh = open(file_name, O_RDONLY | O_BINARY, 0644);
if (fh < 0) {
sprintf(str, "Cannot open file \"%s\"", file_name);
eprintf("%s; %s\n", str, strerror(errno));
return EL_FILE_ERROR;
}
/* read file into buffer */
length = lseek(fh, 0, SEEK_END);
if (length > 0) {
buffer = xmalloc(length + 1);
lseek(fh, 0, SEEK_SET);
read(fh, buffer, length);
buffer[length] = 0;
close(fh);
/* go through buffer */
p = buffer;
do {
p = strstr(p, "$@MID@$:");
if (p) {
lbs->el_index = xrealloc(lbs->el_index, sizeof(EL_INDEX) * (*lbs->n_el_index + 1));
if (lbs->el_index == NULL) {
eprintf("Not enough memory to allocate entry index\n");
return EL_MEM_ERROR;
}
strcpy(str, file_list + index * MAX_PATH_LENGTH);
strcpy(lbs->el_index[*lbs->n_el_index].file_name, str);
el_decode(p, "Date: ", date, sizeof(date));
el_decode_int(p, "In reply to: ", in_reply_to, sizeof(in_reply_to));
lbs->el_index[*lbs->n_el_index].file_time = date_to_ltime(date);
lbs->el_index[*lbs->n_el_index].message_id = atoi(p + 8);
lbs->el_index[*lbs->n_el_index].offset = p - buffer;
lbs->el_index[*lbs->n_el_index].in_reply_to = atoi(in_reply_to);
pn = strstr(p + 8, "$@MID@$:");
if (pn)
len = pn - p;
else
len = strlen(p);
MD5_checksum(p, len, lbs->el_index[*lbs->n_el_index].md5_digest);
if (lbs->el_index[*lbs->n_el_index].message_id > 0) {
if (is_verbose() > 1) {
eprintf(" ID %3d, %s, ofs %5d, %s, MD5=", lbs->el_index[*lbs->n_el_index].message_id,
str, lbs->el_index[*lbs->n_el_index].offset,
lbs->el_index[*lbs->n_el_index].in_reply_to ? "reply" : "thead");
for (i = 0; i < 16; i++)
eprintf("%02X", lbs->el_index[*lbs->n_el_index].md5_digest[i]);
eprintf("\n");
}
/* valid ID */
(*lbs->n_el_index)++;
}
p += 8;
}
} while (p);
xfree(buffer);
}
}
xfree(file_list);
/* sort entries according to date */
qsort(lbs->el_index, *lbs->n_el_index, sizeof(EL_INDEX), eli_compare);
if (is_verbose() > 1) {
eprintf("After sort:\n");
for (i = 0; i < *lbs->n_el_index; i++)
eprintf(" ID %3d, %s, ofs %5d\n", lbs->el_index[i].message_id, lbs->el_index[i].file_name,
lbs->el_index[i].offset);
}
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
int el_index_logbooks()
{
char str[256], data_dir[256], logbook[256], cwd[256], *p;
int i, j, n, status = 0;
if (lb_list) {
for (i = 0; lb_list[i].name[0]; i++) {
if (lb_list[i].el_index != NULL) {
xfree(lb_list[i].el_index);
xfree(lb_list[i].n_el_index);
/* check if other logbook uses same index */
for (j = i + 1; lb_list[j].name[0]; j++) {
/* mark that logbook already freed */
if (lb_list[j].el_index == lb_list[i].el_index)
lb_list[j].el_index = NULL;
}
}
}
xfree(lb_list);
}
/* count logbooks */
for (i = n = 0;; i++) {
if (!enumgrp(i, str))
break;
if (!is_logbook(str))
continue;
n++;
}
lb_list = xcalloc(sizeof(LOGBOOK), n + 1);
for (i = n = 0;; i++) {
if (!enumgrp(i, logbook))
break;
if (!is_logbook(logbook))
continue;
/* check for duplicate name */
for (j = 0; j < i && lb_list[j].name[0]; j++)
if (strieq(lb_list[j].name, logbook)) {
eprintf("Error in configuration file: Duplicate logbook \"%s\"\n", logbook);
return EL_DUPLICATE;
}
/* store logbook in list */
strcpy(lb_list[n].name, logbook);
strcpy(lb_list[n].name_enc, logbook);
url_encode(lb_list[n].name_enc, sizeof(lb_list[n].name_enc));
/* get data dir from configuration file (old method) */
if (getcfg(logbook, "Data dir", str, sizeof(str))) {
if (str[0] == DIR_SEPARATOR || str[1] == ':')
strlcpy(data_dir, str, sizeof(data_dir));
else {
strlcpy(data_dir, resource_dir, sizeof(data_dir));
strlcat(data_dir, str, sizeof(data_dir));
}
} else {
/* use logbook_dir + "Subdir" (new method) */
strlcpy(data_dir, logbook_dir, sizeof(data_dir));
if (data_dir[strlen(data_dir) - 1] != DIR_SEPARATOR)
strlcat(data_dir, DIR_SEPARATOR_STR, sizeof(data_dir));
if (getcfg(logbook, "Subdir", str, sizeof(str))) {
if (str[0] == DIR_SEPARATOR)
strlcpy(data_dir, str, sizeof(data_dir));
else
strlcat(data_dir, str, sizeof(data_dir));
} else
strlcat(data_dir, logbook, sizeof(data_dir)); /* use logbook name as default */
}
if (data_dir[strlen(data_dir) - 1] != DIR_SEPARATOR)
strlcat(data_dir, DIR_SEPARATOR_STR, sizeof(data_dir));
/* create data directory if not existing */
getcwd(cwd, sizeof(cwd));
j = chdir(data_dir);
if (j < 0) {
p = data_dir;
if (*p == DIR_SEPARATOR) {
chdir(DIR_SEPARATOR_STR);
p++;
}
if (p[1] == ':') {
strcpy(str, p);
if (str[2] == DIR_SEPARATOR)
str[3] = 0;
else
str[2] = 0;
chdir(str);
p += strlen(str);
}
do {
if (strchr(p, DIR_SEPARATOR)) {
strlcpy(str, p, sizeof(str));
*strchr(str, DIR_SEPARATOR) = 0;
p = strchr(p, DIR_SEPARATOR) + 1;
} else {
strlcpy(str, p, sizeof(str));
p = NULL;
}
j = chdir(str);
if (j < 0) {
#ifdef OS_WINNT
j = mkdir(str);
#else
j = mkdir(str, 0755);
#endif
if (j == 0) {
if (is_verbose())
eprintf("Created directory \"%s\"\n", str);
} else {
eprintf("el_index_logbooks: %s\n", strerror(errno));
eprintf("Cannot create directory \"%s\"\n", str);
}
chdir(str);
}
} while (p && *p);
}
chdir(cwd);
strcpy(lb_list[n].data_dir, data_dir);
lb_list[n].el_index = NULL;
/* check if other logbook uses the same directory */
for (j = 0; j < n; j++)
if (strcmp(lb_list[j].data_dir, lb_list[n].data_dir) == 0) {
if (is_verbose())
eprintf("Logbook \"%s\" uses same directory as logbook \"%s\"\n", logbook, lb_list[j].name);
lb_list[n].el_index = lb_list[j].el_index;
lb_list[n].n_el_index = lb_list[j].n_el_index;
break;
}
if (j == n) {
if (is_verbose())
eprintf("Indexing logbook \"%s\" in \"%s\" ... ", logbook, lb_list[n].data_dir);
eflush();
status = el_build_index(&lb_list[n], FALSE);
if (is_verbose())
if (status == EL_SUCCESS)
eprintf("ok\n");
}
if (status == EL_EMPTY) {
if (is_verbose())
eprintf("Found empty logbook \"%s\"\n", logbook);
} else if (status == EL_UPGRADE) {
eprintf("Please upgrade data files in \"%s\" with the elconv program.\n", data_dir);
return EL_UPGRADE;
} else if (status != EL_SUCCESS) {
eprintf("Error generating index.\n");
return status;
}
n++;
}
/* if top groups defined, set top group in logbook */
if (exist_top_group()) {
LBLIST phier;
phier = get_logbook_hierarchy();
for (i = 0; i < phier->n_members; i++)
if (phier->member[i]->is_top)
for (j = 0; lb_list[j].name[0]; j++)
if (is_logbook_in_group(phier->member[i], lb_list[j].name))
strcpy(lb_list[j].top_group, phier->member[i]->name);
free_logbook_hierarchy(phier);
}
if (!load_password_files())
return EL_INVAL_FILE;
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
int el_search_message(LOGBOOK * lbs, int mode, int message_id, BOOL head_only)
/********************************************************************
Routine: el_search_message
Purpose: Search for a specific message in a logbook
Input:
int mode Search mode, EL_FIRST, EL_LAST, EL_NEXT, EL_PREV
int message_id Message id for EL_NEXT and EL_PREV
Function value:
int New message id
\********************************************************************/
{
int i;
if (lbs->n_el_index == 0)
return 0;
if (mode == EL_FIRST) {
if (head_only) {
for (i = 0; i < *lbs->n_el_index; i++)
if (lbs->el_index[i].in_reply_to == 0)
return lbs->el_index[i].message_id;
return 0;
}
if (*lbs->n_el_index == 0)
return 0;
return lbs->el_index[0].message_id;
}
if (mode == EL_LAST) {
if (head_only) {
for (i = *lbs->n_el_index - 1; i >= 0; i--)
if (lbs->el_index[i].in_reply_to == 0)
return lbs->el_index[i].message_id;
return 0;
}
if (*lbs->n_el_index == 0)
return 0;
return lbs->el_index[*lbs->n_el_index - 1].message_id;
}
if (mode == EL_NEXT) {
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)
return 0; // message not found
if (i == *lbs->n_el_index - 1)
return 0; // last message
if (head_only) {
for (i++; i < *lbs->n_el_index; i++)
if (lbs->el_index[i].in_reply_to == 0)
return lbs->el_index[i].message_id;
return 0;
}
return lbs->el_index[i + 1].message_id;
}
if (mode == EL_PREV) {
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)
return 0; // message not found
if (i == 0)
return 0; // first message
if (head_only) {
for (i--; i >= 0; i--)
if (lbs->el_index[i].in_reply_to == 0)
return lbs->el_index[i].message_id;
return 0;
}
return lbs->el_index[i - 1].message_id;
}
return 0;
}
/*------------------------------------------------------------------*/
int el_retrieve(LOGBOOK * lbs, int message_id, char *date, char attr_list[MAX_N_ATTR][NAME_LENGTH],
char attrib[MAX_N_ATTR][NAME_LENGTH], int n_attr, char *text, int *textsize,
char *in_reply_to, char *reply_to, char attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH],
char *encoding, char *locked_by)
/********************************************************************
Routine: el_retrieve
Purpose: Retrieve an ELog entry by its message tab
Input:
LOGBOOK lbs Logbook structure
int message_id Message ID to retrieve
int *size Size of text buffer
Output:
char *tag tag of retrieved message
char *date Date/time of message recording
char attr_list Names of attributes
char attrib Values of attributes
int n_attr Number of attributes
char *text Message text
char *in_reply_to Original message if this one is a reply
char *reply_to Replies for current message
char *attachment[] File attachments
char *encoding Encoding of message
char *locked_by User/Host if locked for editing
int *size Actual message text size
Function value:
EL_SUCCESS Successful completion
EL_EMPTY Logbook is empty
EL_NO_MSG Message doesn't exist
EL_FILE_ERROR Internal error
\********************************************************************/
{
int i, index, size, fh;
char str[NAME_LENGTH], file_name[256], *p;
char *message, attachment_all[64 * MAX_ATTACHMENTS];
if (message_id == 0)
/* open most recent message */
message_id = el_search_message(lbs, EL_LAST, 0, FALSE);
if (message_id == 0)
return EL_EMPTY;
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_RDONLY | O_BINARY, 0644);
if (fh < 0) {
/* file might have been deleted, rebuild index */
el_build_index(lbs, TRUE);
return el_retrieve(lbs, message_id, date, attr_list, attrib, n_attr, text, textsize, in_reply_to,
reply_to, attachment, encoding, locked_by);
}
message = xmalloc(TEXT_SIZE + 1000);
lseek(fh, lbs->el_index[index].offset, SEEK_SET);
i = my_read(fh, message, TEXT_SIZE + 1000 - 1);
if (i <= 0) {
xfree(message);
close(fh);
return EL_FILE_ERROR;
}
message[i] = 0;
close(fh);
if (strncmp(message, "$@MID@$:", 8) != 0) {
xfree(message);
/* file might have been edited, rebuild index */
el_build_index(lbs, TRUE);
return el_retrieve(lbs, message_id, date, attr_list, attrib, n_attr, text, textsize, in_reply_to,
reply_to, attachment, encoding, locked_by);
}
/* check for correct ID */
if (atoi(message + 8) != message_id) {
xfree(message);
return EL_FILE_ERROR;
}
/* decode message size */
p = strstr(message + 8, "$@MID@$:");
if (p == NULL)
size = strlen(message);
else
size = p - message;
message[size] = 0;
/* decode message */
if (date)
el_decode(message, "Date: ", date, 80);
if (reply_to)
el_decode_intlist(message, "Reply to: ", reply_to, MAX_REPLY_TO * 10);
if (in_reply_to)
el_decode_int(message, "In reply to: ", in_reply_to, 80);
if (n_attr == -1) {
/* derive attribute names from message */
for (i = 0;; i++) {
el_enum_attr(message, i, attr_list[i], attrib[i]);
if (!attr_list[i][0])
break;
}
n_attr = i;
} else {
if (attrib)
for (i = 0; i < n_attr; i++) {
sprintf(str, "%s: ", attr_list[i]);
el_decode(message, str, attrib[i], NAME_LENGTH);
}
}
el_decode(message, "Attachment: ", attachment_all, sizeof(attachment_all));
if (encoding)
el_decode(message, "Encoding: ", encoding, 80);
if (attachment) {
/* break apart attachements */
for (i = 0; i < MAX_ATTACHMENTS; i++)
if (attachment[i] != NULL)
attachment[i][0] = 0;
for (i = 0; i < MAX_ATTACHMENTS; i++) {
if (attachment[i] != NULL) {
if (i == 0)
p = strtok(attachment_all, ",");
else
p = strtok(NULL, ",");
if (p != NULL)
strcpy(attachment[i], p);
else
break;
}
}
}
if (locked_by)
el_decode(message, "Locked by: ", locked_by, 80);
p = strstr(message, "========================================\n");
/* check for \n -> \r conversion (e.g. zipping/unzipping) */
if (p == NULL)
p = strstr(message, "========================================\r");
if (text) {
if (p != NULL) {
p += 41;
if ((int) strlen(p) >= *textsize) {
strlcpy(text, p, *textsize);
show_error("Entry too long to display. Please increase TEXT_SIZE and recompile elogd.");
xfree(message);
return EL_FILE_ERROR;
} else {
strlcpy(text, p, *textsize);
/* strip CR at end */
if (text[strlen(text) - 1] == '\n') {
text[strlen(text) - 1] = 0;
if (text[strlen(text) - 1] == '\r')
text[strlen(text) - 1] = 0;
}
*textsize = strlen(text);
}
} else {
text[0] = 0;
*textsize = 0;
}
}
xfree(message);
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
int el_submit_attachment(LOGBOOK * lbs, const char *afilename, const char *buffer, int buffer_size,
char *full_name)
{
char file_name[MAX_PATH_LENGTH], ext_file_name[MAX_PATH_LENGTH + 100], str[MAX_PATH_LENGTH], *p;
int fh;
time_t now;
struct tm tms;
/* strip directory, add date and time to filename */
strlcpy(str, afilename, sizeof(str));
p = str;
while (strchr(p, ':'))
p = strchr(p, ':') + 1;
while (strchr(p, '\\'))
p = strchr(p, '\\') + 1; /* NT */
while (strchr(p, '/'))
p = strchr(p, '/') + 1; /* Unix */
strlcpy(file_name, p, sizeof(file_name));
/* assemble ELog filename */
if (file_name[0]) {
if (file_name[6] == '_' && file_name[13] == '_' && isdigit(file_name[0]) && isdigit(file_name[1]))
strlcpy(ext_file_name, file_name, sizeof(ext_file_name));
else {
time(&now);
memcpy(&tms, localtime(&now), sizeof(struct tm));
sprintf(ext_file_name, "%02d%02d%02d_%02d%02d%02d_%s", tms.tm_year % 100, tms.tm_mon + 1,
tms.tm_mday, tms.tm_hour, tms.tm_min, tms.tm_sec, file_name);
}
if (full_name)
strlcpy(full_name, ext_file_name, MAX_PATH_LENGTH);
strlcpy(str, lbs->data_dir, sizeof(str));
strlcat(str, ext_file_name, sizeof(str));
/* save attachment */
fh = open(str, O_CREAT | O_RDWR | O_BINARY, 0644);
if (fh < 0) {
strencode2(file_name, str, sizeof(file_name));
sprintf(str, "Cannot write attachment file \"%s\"", file_name);
show_error(str);
return -1;
} else {
write(fh, buffer, buffer_size);
close(fh);
}
}
return 0;
}
/*------------------------------------------------------------------*/
void el_delete_attachment(LOGBOOK * lbs, char *file_name)
{
int i;
char str[MAX_PATH_LENGTH];
strlcpy(str, lbs->data_dir, sizeof(str));
strlcat(str, file_name, sizeof(str));
remove(str);
strlcat(str, ".png", sizeof(str));
remove(str);
for (i = 0;; i++) {
strlcpy(str, lbs->data_dir, sizeof(str));
strlcat(str, file_name, sizeof(str));
sprintf(str + strlen(str), "-%d.png", i);
if (file_exist(str)) {
remove(str);
continue;
}
strlcpy(str, lbs->data_dir, sizeof(str));
strlcat(str, file_name, sizeof(str));
if (strrchr(str, '.'))
*strrchr(str, '.') = 0;
sprintf(str + strlen(str), "-%d.png", i);
if (file_exist(str)) {
remove(str);
continue;
}
break;
}
}
/*------------------------------------------------------------------*/
int el_retrieve_attachment(LOGBOOK * lbs, int message_id, int n, char name[MAX_PATH_LENGTH])
{
int i, index, size, fh;
char file_name[256], *p;
char message[TEXT_SIZE + 1000], attachment_all[64 * MAX_ATTACHMENTS];
if (message_id == 0)
return EL_EMPTY;
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_RDONLY | O_BINARY, 0644);
if (fh < 0) {
/* file might have been deleted, rebuild index */
el_build_index(lbs, TRUE);
return el_retrieve_attachment(lbs, message_id, n, name);
}
lseek(fh, lbs->el_index[index].offset, SEEK_SET);
i = my_read(fh, message, sizeof(message) - 1);
if (i <= 0) {
close(fh);
return EL_FILE_ERROR;
}
message[i] = 0;
close(fh);
if (strncmp(message, "$@MID@$:", 8) != 0) {
/* file might have been edited, rebuild index */
el_build_index(lbs, TRUE);
return el_retrieve_attachment(lbs, message_id, n, name);
}
/* check for correct ID */
if (atoi(message + 8) != message_id)
return EL_FILE_ERROR;
/* decode message size */
p = strstr(message + 8, "$@MID@$:");
if (p == NULL)
size = strlen(message);
else
size = p - message;
message[size] = 0;
el_decode(message, "Attachment: ", attachment_all, sizeof(attachment_all));
name[0] = 0;
for (i = 0; i <= n; i++) {
if (i == 0)
p = strtok(attachment_all, ",");
else
p = strtok(NULL, ",");
if (p == NULL)
break;
}
if (p)
strlcpy(name, p, MAX_PATH_LENGTH);
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
int el_submit(LOGBOOK * lbs, int message_id, BOOL bedit, char *date, char attr_name[MAX_N_ATTR][NAME_LENGTH],
char attr_value[MAX_N_ATTR][NAME_LENGTH], int n_attr, char *text, char *in_reply_to,
char *reply_to, char *encoding, char afilename[MAX_ATTACHMENTS][256], BOOL mark_original,
char *locked_by)
/********************************************************************
Routine: el_submit
Purpose: Submit an ELog entry
Input:
LOGBOOK lbs Logbook structure
int message_id Message id
BOOL bedit TRUE for existing message, FALSE for new message
char *date Message date
char attr_name[][] Name of attributes
char attr_value[][] Value of attributes
int n_attr Number of attributes
char *text Message text
char *in_reply_to In reply to this message
char *reply_to Replie(s) to this message
char *encoding Text encoding, either HTML or plain
char *afilename[] File name of attachments
char *tag If given, edit existing message
int *tag_size Maximum size of tag
BOOL mark_original Tag original message for replies
char *locked_by User/Host which locked message for edit
Function value:
int New message ID
\********************************************************************/
{
int n, i, j, size, fh, index, tail_size, orig_size, delta, reply_id;
char file_name[256], dir[256], str[NAME_LENGTH], date1[256], attrib[MAX_N_ATTR][NAME_LENGTH],
reply_to1[MAX_REPLY_TO * 10], in_reply_to1[MAX_REPLY_TO * 10], encoding1[80], *message, *p,
*old_text, *buffer;
char attachment_all[64 * MAX_ATTACHMENTS];
time_t ltime;
tail_size = orig_size = 0;
buffer = NULL;
message = xmalloc(TEXT_SIZE + 100);
old_text = NULL;
memcpy(attrib, attr_value, sizeof(attrib));
strlcpy(reply_to1, reply_to, sizeof(reply_to1));
strlcpy(in_reply_to1, in_reply_to, sizeof(in_reply_to1));
strlcpy(encoding1, encoding, sizeof(encoding1));
strlcpy(date1, date, sizeof(date1));
/* generate new file name YYMMDD.log in data directory */
strcpy(dir, lbs->data_dir);
if (bedit) {
/* edit existing message */
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) {
xfree(message);
return -1;
}
sprintf(file_name, "%s%s", lbs->data_dir, lbs->el_index[index].file_name);
fh = open(file_name, O_CREAT | O_RDWR | O_BINARY, 0644);
if (fh < 0) {
xfree(message);
return -1;
}
lseek(fh, lbs->el_index[index].offset, SEEK_SET);
i = my_read(fh, message, TEXT_SIZE + 100 - 1);
if (i >= 0)
message[i] = 0;
else
message[0] = 0;
/* check for valid message */
if (strncmp(message, "$@MID@$:", 8) != 0) {
close(fh);
xfree(message);
/* file might have been edited, rebuild index */
el_build_index(lbs, TRUE);
return el_submit(lbs, message_id, bedit, date, attr_name, attrib, n_attr, text, in_reply_to,
reply_to, encoding, afilename, mark_original, locked_by);
}
/* check for correct ID */
if (atoi(message + 8) != message_id) {
close(fh);
xfree(message);
return -1;
}
/* decode message size */
p = strstr(message + 8, "$@MID@$:");
if (p == NULL)
size = strlen(message);
else
size = p - message;
message[size] = 0;
if (strcmp(text, "") == 0) {
p = strstr(message, "========================================\n");
/* check for \n -> \r conversion (e.g. zipping/unzipping) */
if (p == NULL)
p = strstr(message, "========================================\r");
if (p) {
p += 41;
old_text = xmalloc(size + 1);
strlcpy(old_text, p, size);
if (old_text[strlen(old_text) - 1] == '\n' || old_text[strlen(old_text) - 1] == '\r')
old_text[strlen(old_text) - 1] = 0;
}
}
if (strieq(date1, ""))
el_decode(message, "Date: ", date1, sizeof(date1));
else
strlcpy(date1, date, sizeof(date1));
if (strieq(reply_to1, ""))
el_decode_intlist(message, "Reply to: ", reply_to1, sizeof(reply_to1));
if (strieq(in_reply_to1, ""))
el_decode_int(message, "In reply to: ", in_reply_to1, sizeof(in_reply_to1));
if (strieq(encoding1, ""))
el_decode(message, "Encoding: ", encoding1, sizeof(encoding1));
el_decode(message, "Attachment: ", attachment_all, sizeof(attachment_all));
for (i = 0; i < n_attr; i++) {
sprintf(str, "%s: ", attr_name[i]);
if (strieq(attrib[i], ""))
el_decode(message, str, attrib[i], NAME_LENGTH);
}
/* buffer tail of logfile */
lseek(fh, 0, SEEK_END);
orig_size = size;
tail_size = TELL(fh) - (lbs->el_index[index].offset + size);
if (tail_size > 0) {
buffer = xmalloc(tail_size);
lseek(fh, lbs->el_index[index].offset + size, SEEK_SET);
n = my_read(fh, buffer, tail_size);
}
lseek(fh, lbs->el_index[index].offset, SEEK_SET);
} else {
/* create new message */
if (!date[0]) {
get_rfc2822_date(date1, sizeof(date1), 0);
ltime = date_to_ltime(date1);
} else {
ltime = date_to_ltime(date);
get_rfc2822_date(date1, sizeof(date1), ltime);
}
for (i = 0; i < 12; i++)
if (strncmp(date1 + 8, mname[i], 3) == 0)
break;
sprintf(file_name, "%c%c%02d%c%ca.log", date1[14], date1[15], i + 1, date1[5], date1[6]);
sprintf(str, "%s%s", dir, file_name);
fh = open(str, O_CREAT | O_RDWR | O_BINARY, 0644);
if (fh < 0) {
xfree(message);
if (old_text)
xfree(old_text);
return -1;
}
lseek(fh, 0, SEEK_END);
/* new message id is old plus one */
if (message_id == 0) {
message_id = 1;
for (i = 0; i < *lbs->n_el_index; i++)
if (lbs->el_index[i].message_id >= message_id)
message_id = lbs->el_index[i].message_id + 1;
}
/* enter message in index */
index = *lbs->n_el_index;
(*lbs->n_el_index)++;
lbs->el_index = xrealloc(lbs->el_index, sizeof(EL_INDEX) * (*lbs->n_el_index));
lbs->el_index[index].message_id = message_id;
strcpy(lbs->el_index[index].file_name, file_name);
lbs->el_index[index].file_time = ltime;
lbs->el_index[index].offset = TELL(fh);
lbs->el_index[index].in_reply_to = atoi(in_reply_to1);
/* if index not ordered, sort it */
i = *lbs->n_el_index;
if (i > 1 && lbs->el_index[i - 1].file_time < lbs->el_index[i - 2].file_time) {
qsort(lbs->el_index, i, sizeof(EL_INDEX), eli_compare);
/* search message again, index could have been changed by sorting */
for (index = 0; index < *lbs->n_el_index; index++)
if (lbs->el_index[index].message_id == message_id)
break;
}
/* if other logbook has same index, update pointers */
for (i = 0; lb_list[i].name[0]; i++)
if (&lb_list[i] != lbs && lb_list[i].n_el_index == lbs->n_el_index)
lb_list[i].el_index = lbs->el_index;
}
/* compose message */
sprintf(message, "$@MID@$: %d\n", message_id);
sprintf(message + strlen(message), "Date: %s\n", date1);
if (reply_to1[0])
sprintf(message + strlen(message), "Reply to: %s\n", reply_to1);
if (in_reply_to1[0])
sprintf(message + strlen(message), "In reply to: %s\n", in_reply_to1);
for (i = 0; i < n_attr; i++)
sprintf(message + strlen(message), "%s: %s\n", attr_name[i], attrib[i]);
sprintf(message + strlen(message), "Attachment: ");
if (afilename) {
sprintf(message + strlen(message), "%s", afilename[0]);
for (i = 1; i < MAX_ATTACHMENTS; i++)
if (afilename[i][0])
sprintf(message + strlen(message), ",%s", afilename[i]);
}
sprintf(message + strlen(message), "\n");
sprintf(message + strlen(message), "Encoding: %s\n", encoding1);
if (locked_by && locked_by[0])
sprintf(message + strlen(message), "Locked by: %s\n", locked_by);
sprintf(message + strlen(message), "========================================\n");
if (strieq(text, "") && old_text)
strlcat(message, old_text, TEXT_SIZE + 100);
else
strlcat(message, text, TEXT_SIZE + 100);
strlcat(message, "\n", TEXT_SIZE + 100);
if (old_text)
xfree(old_text);
n = write(fh, message, strlen(message));
if (n != (int) strlen(message)) {
if (tail_size > 0)
xfree(buffer);
close(fh);
return -1;
}
/* update MD5 checksum */
MD5_checksum(message, strlen(message), lbs->el_index[index].md5_digest);
if (bedit) {
if (tail_size > 0) {
n = write(fh, buffer, tail_size);
xfree(buffer);
/* correct offsets for remaining messages in same file */
delta = strlen(message) - orig_size;
for (i = 0; i < *lbs->n_el_index; i++)
if (lbs->el_index[i].message_id == message_id)
break;
for (j = i + 1; j < *lbs->n_el_index && strieq(lbs->el_index[i].file_name,
lbs->el_index[j].file_name); j++)
lbs->el_index[j].offset += delta;
}
/* truncate file here */
TRUNCATE(fh);
}
close(fh);
/* if reply, mark original message */
reply_id = atoi(in_reply_to);
if (mark_original && in_reply_to[0] && !bedit && atoi(in_reply_to) > 0) {
char date[80], attr[MAX_N_ATTR][NAME_LENGTH], enc[80], att[MAX_ATTACHMENTS][256],
reply_to[MAX_REPLY_TO * 10], in_reply_to[MAX_REPLY_TO * 10], lock[256];
/* retrieve original message */
size = TEXT_SIZE + 100;
el_retrieve(lbs, reply_id, date, attr_list, attr, n_attr, message, &size, in_reply_to, reply_to, att,
enc, lock);
if (reply_to[0])
strcat(reply_to, ", ");
sprintf(reply_to + strlen(reply_to), "%d", message_id);
/* write modified message */
el_submit(lbs, reply_id, TRUE, date, attr_list, attr, n_attr, message, in_reply_to, reply_to, enc, att,
TRUE, lock);
}
xfree(message);
return message_id;
}
/*------------------------------------------------------------------*/
void remove_reference(LOGBOOK * lbs, int message_id, int remove_id, BOOL reply_to_flag)
{
char date[80], attr[MAX_N_ATTR][NAME_LENGTH], enc[80], in_reply_to[80], reply_to[MAX_REPLY_TO * 10],
att[MAX_ATTACHMENTS][256], lock[256], *p, *ps, *message;
int size, status;
/* retrieve original message */
size = TEXT_SIZE + 1000;
message = (char *) xmalloc(size);
status = el_retrieve(lbs, message_id, date, attr_list, attr, lbs->n_attr, message, &size, in_reply_to,
reply_to, att, enc, lock);
if (status != EL_SUCCESS)
return;
if (reply_to_flag)
p = reply_to;
else
p = in_reply_to;
while (*p) {
while (*p && (*p == ',' || *p == ' '))
p++;
ps = p;
while (isdigit(*ps))
ps++;
while (*ps && (*ps == ',' || *ps == ' '))
ps++;
if (atoi(p) == remove_id)
strcpy(p, ps);
else
while (isdigit(*p))
p++;
}
/* write modified message */
el_submit(lbs, message_id, TRUE, date, attr_list, attr, lbs->n_attr, message, in_reply_to, reply_to, enc,
att, TRUE, lock);
xfree(message);
}
/*------------------------------------------------------------------*/
int el_delete_message(LOGBOOK * lbs, int message_id, BOOL delete_attachments,
char attachment[MAX_ATTACHMENTS][MAX_PATH_LENGTH], BOOL delete_bw_ref,
BOOL delete_reply_to)
/********************************************************************
Routine: el_delete_message
Purpose: Delete an ELog entry including attachments
Input:
LOGBOOK *lbs Pointer to logbook structure
int message_id Message ID
BOOL delete_attachments Delete attachments if TRUE
char attachment Used to return attachments (on move)
BOOL delete_bw_ref If true, delete backward references
BOOL delete_reply_to If true, delete replies to this message
Output:
Function value:
EL_SUCCESS Successful completion
\********************************************************************/
{
int i, index, n, size, fh, tail_size, old_offset, n_attr;
char str[MAX_PATH_LENGTH], file_name[MAX_PATH_LENGTH], reply_to[MAX_REPLY_TO * 10], in_reply_to[256];
char *buffer, *p;
char *message, attachment_all[64 * MAX_ATTACHMENTS];
char attrib[MAX_N_ATTR][NAME_LENGTH];
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 -1;
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;
message = xmalloc(TEXT_SIZE + 1000);
lseek(fh, lbs->el_index[index].offset, SEEK_SET);
i = my_read(fh, message, TEXT_SIZE + 1000 - 1);
if (i <= 0) {
xfree(message);
close(fh);
return EL_FILE_ERROR;
}
if (_logging_level > 1) {
sprintf(str, "DELETE entry #%d", message_id);
write_logfile(lbs, str);
}
message[i] = 0;
if (strncmp(message, "$@MID@$:", 8) != 0) {
close(fh);
xfree(message);
/* file might have been edited, rebuild index */
el_build_index(lbs, TRUE);
return el_delete_message(lbs, message_id, delete_attachments, attachment, delete_bw_ref,
delete_reply_to);
}
/* check for correct ID */
if (atoi(message + 8) != message_id) {
close(fh);
xfree(message);
return EL_FILE_ERROR;
}
/* decode message size */
p = strstr(message + 8, "$@MID@$:");
if (p == NULL)
size = strlen(message);
else
size = p - message;
message[size] = 0;
/* delete attachments */
el_decode(message, "Attachment: ", attachment_all, sizeof(attachment_all));
for (i = 0; i < MAX_ATTACHMENTS; i++) {
if (i == 0)
p = strtok(attachment_all, ",");
else
p = strtok(NULL, ",");
if (attachment != NULL) {
if (attachment[i][0] && p) {
/* delete old attachment if new one exists */
el_delete_attachment(lbs, p);
}
/* return old attachment if no new one */
if (!attachment[i][0] && p)
strcpy(attachment[i], p);
}
if (delete_attachments && p)
el_delete_attachment(lbs, p);
}
/* decode references */
el_decode_intlist(message, "Reply to: ", reply_to, sizeof(reply_to));
el_decode_int(message, "In reply to: ", in_reply_to, sizeof(in_reply_to));
/* decoded attributes */
for (i = 0;; i++) {
el_enum_attr(message, i, attr_list[i], attrib[i]);
if (!attr_list[i][0])
break;
}
n_attr = i;
/* buffer tail of logfile */
lseek(fh, 0, SEEK_END);
tail_size = TELL(fh) - (lbs->el_index[index].offset + size);
buffer = NULL;
if (tail_size > 0) {
buffer = xmalloc(tail_size);
lseek(fh, lbs->el_index[index].offset + size, SEEK_SET);
n = my_read(fh, buffer, tail_size);
}
lseek(fh, lbs->el_index[index].offset, SEEK_SET);
if (tail_size > 0) {
n = write(fh, buffer, tail_size);
xfree(buffer);
}
/* truncate file here */
TRUNCATE(fh);
/* if file length gets zero, delete file */
tail_size = lseek(fh, 0, SEEK_END);
close(fh);
xfree(message);
if (tail_size == 0)
remove(file_name);
/* remove message from index */
strcpy(str, lbs->el_index[index].file_name);
old_offset = lbs->el_index[index].offset;
for (i = index; i < *lbs->n_el_index - 1; i++)
memcpy(&lbs->el_index[i], &lbs->el_index[i + 1], sizeof(EL_INDEX));
(*lbs->n_el_index)--;
if (*lbs->n_el_index > 0)
lbs->el_index = xrealloc(lbs->el_index, sizeof(EL_INDEX) * (*lbs->n_el_index));
/* correct all offsets after deleted message */
for (i = 0; i < *lbs->n_el_index; i++)
if (strieq(lbs->el_index[i].file_name, str) && lbs->el_index[i].offset > old_offset)
lbs->el_index[i].offset -= size;
/* if other logbook has same index, update pointers */
for (i = 0; lb_list[i].name[0]; i++)
if (&lb_list[i] != lbs && lb_list[i].n_el_index == lbs->n_el_index)
lb_list[i].el_index = lbs->el_index;
/* delete also replies to this message */
if (delete_reply_to && reply_to[0]) {
p = reply_to;
if (isdigit(*p))
do {
if (atoi(p))
el_delete_message(lbs, atoi(p), TRUE, NULL, FALSE, TRUE);
while (*p && isdigit(*p))
p++;
while (*p && (*p == ',' || *p == ' '))
p++;
} while (*p);
}
/* delete backward references */
if (in_reply_to[0] && delete_bw_ref) {
p = in_reply_to;
do {
if (atoi(p))
remove_reference(lbs, atoi(p), message_id, TRUE);
while (*p && isdigit(*p))
p++;
while (*p && (*p == ',' || *p == ' '))
p++;
} while (*p);
}
/* execute shell if requested */
if (getcfg(lbs->name, "Execute delete", str, sizeof(str)))
execute_shell(lbs, message_id, attrib, NULL, str);
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
int el_correct_links(LOGBOOK * lbs, int old_id, int new_id)
/* If a message gets resubmitted, the links to that message are wrong.
This routine corrects that. */
{
int i, i1, n, n1, size;
char date[80], *attrib, *text, in_reply_to[80], reply_to[MAX_REPLY_TO * 10], encoding[80], locked_by[256];
char list[MAX_N_ATTR][NAME_LENGTH], list1[MAX_N_ATTR][NAME_LENGTH];
char *att_file;
attrib = (char *) xmalloc(MAX_N_ATTR * NAME_LENGTH);
text = (char *) xmalloc(TEXT_SIZE);
att_file = (char *) xmalloc(MAX_ATTACHMENTS * 256);
el_retrieve(lbs, new_id, date, attr_list, (char (*)[1500]) attrib, lbs->n_attr, NULL, 0, in_reply_to,
reply_to, (char (*)[256]) att_file, encoding, locked_by);
/* go through in_reply_to list */
n = strbreak(in_reply_to, list, MAX_N_ATTR, ",", FALSE);
for (i = 0; i < n; i++) {
size = TEXT_SIZE;
el_retrieve(lbs, atoi(list[i]), date, attr_list, (char (*)[1500]) attrib, lbs->n_attr, text, &size,
in_reply_to, reply_to, (char (*)[256]) att_file, encoding, locked_by);
n1 = strbreak(reply_to, list1, MAX_N_ATTR, ",", FALSE);
reply_to[0] = 0;
for (i1 = 0; i1 < n1; i1++) {
/* replace old ID by new ID */
if (atoi(list1[i1]) == old_id)
sprintf(reply_to + strlen(reply_to), "%d", new_id);
else
strcat(reply_to, list1[i1]);
if (i1 < n1 - 1)
strcat(reply_to, ", ");
}
el_submit(lbs, atoi(list[i]), TRUE, date, attr_list, (char (*)[1500]) attrib, lbs->n_attr, text,
in_reply_to, reply_to, encoding, (char (*)[256]) att_file, TRUE, locked_by);
}
el_retrieve(lbs, new_id, date, attr_list, (char (*)[1500]) attrib, lbs->n_attr, NULL, 0, in_reply_to,
reply_to, (char (*)[256]) att_file, encoding, locked_by);
/* go through reply_to list */
n = strbreak(reply_to, list, MAX_N_ATTR, ",", FALSE);
for (i = 0; i < n; i++) {
size = sizeof(text);
el_retrieve(lbs, atoi(list[i]), date, attr_list, (char (*)[1500]) attrib, lbs->n_attr, text, &size,
in_reply_to, reply_to, (char (*)[256]) att_file, encoding, locked_by);
n1 = strbreak(in_reply_to, list1, MAX_N_ATTR, ",", FALSE);
in_reply_to[0] = 0;
for (i1 = 0; i1 < n1; i1++) {
/* replace old ID by new ID */
if (atoi(list1[i1]) == old_id)
sprintf(in_reply_to + strlen(in_reply_to), "%d", new_id);
else
strcat(in_reply_to, list1[i1]);
if (i1 < n1 - 1)
strcat(in_reply_to, ", ");
}
el_submit(lbs, atoi(list[i]), TRUE, date, attr_list, (char (*)[1500]) attrib, lbs->n_attr, text,
in_reply_to, reply_to, encoding, (char (*)[256]) att_file, TRUE, locked_by);
}
xfree(text);
xfree(attrib);
xfree(att_file);
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
int el_move_message_thread(LOGBOOK * lbs, int message_id)
{
int i, n, size, new_id;
char date[80], attrib[MAX_N_ATTR][NAME_LENGTH], *text, in_reply_to[80], reply_to[MAX_REPLY_TO * 10],
encoding[80], locked_by[256];
char list[MAX_N_ATTR][NAME_LENGTH], str[256];
char att_file[MAX_ATTACHMENTS][256];
/* retrieve message */
text = xmalloc(TEXT_SIZE);
size = TEXT_SIZE;
el_retrieve(lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to, reply_to,
att_file, encoding, locked_by);
/* submit as new message */
date[0] = 0;
new_id = el_submit(lbs, 0, FALSE, date, attr_list, attrib, lbs->n_attr, text, in_reply_to, reply_to,
encoding, att_file, FALSE, locked_by);
xfree(text);
/* correct links */
el_correct_links(lbs, message_id, new_id);
/* delete original message */
el_delete_message(lbs, message_id, FALSE, NULL, FALSE, FALSE);
/* move all replies recursively */
if (getcfg(lbs->name, "Resubmit replies", str, sizeof(str)) && atoi(str) == 1) {
if (reply_to[0]) {
n = strbreak(reply_to, list, MAX_N_ATTR, ",", FALSE);
for (i = 0; i < n; i++)
el_move_message_thread(lbs, atoi(list[i]));
}
}
return new_id;
}
/*------------------------------------------------------------------*/
int el_move_message(LOGBOOK * lbs, int old_id, int new_id)
{
int status, size;
char date[80], attrib[MAX_N_ATTR][NAME_LENGTH], *text, in_reply_to[80], reply_to[MAX_REPLY_TO * 10],
encoding[80], locked_by[256], att_file[MAX_ATTACHMENTS][256];
/* retrieve message */
text = xmalloc(TEXT_SIZE);
size = TEXT_SIZE;
status = el_retrieve(lbs, old_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to,
reply_to, att_file, encoding, locked_by);
if (status != EL_SUCCESS)
return 0;
/* submit as new message */
status = el_submit(lbs, new_id, FALSE, date, attr_list, attrib, lbs->n_attr, text, in_reply_to, reply_to,
encoding, att_file, FALSE, locked_by);
xfree(text);
if (status != new_id)
return 0;
/* correct links */
el_correct_links(lbs, old_id, new_id);
/* delete original message */
el_delete_message(lbs, old_id, FALSE, NULL, FALSE, FALSE);
return 1;
}
/*------------------------------------------------------------------*/
int el_lock_message(LOGBOOK * lbs, int message_id, char *user)
/* lock message for editing */
{
int size;
char date[80], attrib[MAX_N_ATTR][NAME_LENGTH], text[TEXT_SIZE], in_reply_to[80],
reply_to[MAX_REPLY_TO * 10], encoding[80], locked_by[256];
char att_file[MAX_ATTACHMENTS][256];
/* retrieve message */
size = sizeof(text);
el_retrieve(lbs, message_id, date, attr_list, attrib, lbs->n_attr, text, &size, in_reply_to, reply_to,
att_file, encoding, locked_by);
/* submit message, unlocked if user==NULL */
el_submit(lbs, message_id, TRUE, date, attr_list, attrib, lbs->n_attr, text, in_reply_to, reply_to,
encoding, att_file, FALSE, user);
return EL_SUCCESS;
}
/*------------------------------------------------------------------*/
void write_logfile(LOGBOOK * lbs, const char *text)
{
char file_name[MAX_PATH_LENGTH];
char str[MAX_PATH_LENGTH], unm[256];
int fh;
time_t now;
char buf[10000];
if (lbs == NULL) {
if (!getcfg("global", "logfile", str, sizeof(str)))
return;
} else if (!getcfg(lbs->name, "logfile", str, sizeof(str)))
return;
if (str[0] == DIR_SEPARATOR || str[1] == ':')
strlcpy(file_name, str, sizeof(file_name));
else {
strlcpy(file_name, logbook_dir, sizeof(file_name));
strlcat(file_name, str, sizeof(file_name));
}
fh = open(file_name, O_RDWR | O_BINARY | O_CREAT | O_APPEND, 0644);
if (fh < 0)
return;
now = time(0);
strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", localtime(&now));
strcat(buf, " ");
if (isparam("unm") && rem_host[0]) {
strlcpy(unm, getparam("unm"), sizeof(unm));
if (rem_host_ip[0])
sprintf(buf + strlen(buf), "[%s@%s(%s)] ", unm, rem_host, rem_host_ip);
else
sprintf(buf + strlen(buf), "[%s@%s] ", unm, rem_host);
} else if (rem_host[0]) {
if (rem_host_ip[0])
sprintf(buf + strlen(buf), "[%s(%s)] ", rem_host, rem_host_ip);
else
sprintf(buf + strlen(buf), "[%s] ", rem_host);
} else
sprintf(buf + strlen(buf), "[%s] ", rem_host_ip);
if (lbs)
sprintf(buf + strlen(buf), "{%s} ", lbs->name);
strlcat(buf, text, sizeof(buf) - 1);
#ifdef OS_WINNT
if (strlen(buf) > 0 && buf[strlen(buf) - 1] != '\n')
strlcat(buf, "\r\n", sizeof(buf));
else if (strlen(buf) > 1 && buf[strlen(buf) - 2] != '\r')
strlcpy(buf + strlen(buf) - 2, "\r\n", sizeof(buf) - (strlen(buf) - 2));
#else
if (strlen(buf) > 1 && buf[strlen(buf) - 1] != '\n')
strlcat(buf, "\n", sizeof(buf));
#endif
write(fh, buf, strlen(buf));
close(fh);
}
/*------------------------------------------------------------------*/
/*
void logd(const char *format, ...)
{
va_list argptr;
char str[10000];
FILE *f;
time_t now;
char buf[1000];
va_start(argptr, format);
vsprintf(str, (char *) format, argptr);
va_end(argptr);
f = fopen("c:\\tmp\\elogd.log", "a");
if (!f)
return;
now = time(0);
strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", localtime(&now));
strcat(buf, " ");
strlcat(buf, str, sizeof(buf));
if (buf[strlen(buf) - 1] != '\n')
strlcat(buf, "\n", sizeof(buf));
fprintf(f, buf);
fclose(f);
}
*/
/*------------------------------------------------------------------*/
char *html_tags[] = { "", "", "", "
", "
", "" };
int is_html(char *s)
{
char *str, *p;
int i;
str = xstrdup(s);
for (i = 0; i < (int) strlen(s); i++)
str[i] = toupper(s[i]);
str[i] = 0;
for (i = 0; html_tags[i][0]; i++) {
p = strstr(str, html_tags[i]);
if (p && strchr(p, '>') && (p == str || (p > str && *(p - 1) != '\\'))) {
xfree(str);
return TRUE;
}
}
xfree(str);
return FALSE;
}
/*------------------------------------------------------------------*/
int html_allowed(LOGBOOK * lbs)
{
char str[80];
return (getcfg(lbs->name, "Allow HTML", str, sizeof(str)) && atoi(str) == 1);
}
/*------------------------------------------------------------------*/
char *script_tags[] = { "onerror", "onabort", "onchange", "onclick", "ondblclick", "onfocus", "onkeydown",
"onkeyup", "onload", "onmousedonw", "onmousemove", "onmouseover", "onmouseup",
"onreset", "onselect", "onsubmit", "onunload", "javascript", NULL
};
int is_script(char *s)
{
char *str;
int i;
str = xstrdup(s);
for (i = 0; i < (int) strlen(s); i++)
str[i] = tolower(s[i]);
str[i] = 0;
for (i = 0; script_tags[i] != NULL; i++) {
if (strstr(str, script_tags[i])) {
xfree(str);
return TRUE;
}
}
xfree(str);
return FALSE;
}
/*------------------------------------------------------------------*/
char *full_html_tags[] = { "", "", "", "" };
int is_full_html(char *file_name)
{
char *str, *p;
int i, fh, length;
unsigned char *buf;
fh = open(file_name, O_RDONLY | O_BINARY);
if (fh < 0)
return FALSE;
lseek(fh, 0, SEEK_END);
length = TELL(fh);
lseek(fh, 0, SEEK_SET);
if (length > 1000)
length = 1000;
buf = xmalloc(length);
read(fh, buf, length);
close(fh);
str = xstrdup((char *) buf);
for (i = 0; i < (int) strlen((char *) buf); i++)
str[i] = toupper(buf[i]);
str[i] = 0;
xfree(buf);
for (i = 0; full_html_tags[i][0]; i++) {
p = strstr(str, full_html_tags[i]);
if (p && strchr(p, '>') && (p == str || (p > str && *(p - 1) != '\\'))) {
xfree(str);
return TRUE;
}
}
xfree(str);
return FALSE;
}
/*------------------------------------------------------------------*/
int is_ascii(char *file_name)
{
int i, fh, length;
unsigned char *buf;
fh = open(file_name, O_RDONLY | O_BINARY);
if (fh < 0)
return FALSE;
lseek(fh, 0, SEEK_END);
length = TELL(fh);
lseek(fh, 0, SEEK_SET);
if (length > 1000)
length = 1000;
buf = xmalloc(length);
read(fh, buf, length);
close(fh);
for (i = 0; i < length; i++) {
if (buf[i] < 32 && buf[i] != '\r' && buf[i] != '\n' && buf[i] != '\t') {
xfree(buf);
return FALSE;
}
}
xfree(buf);
return TRUE;
}
/*------------------------------------------------------------------*/
int is_image(char *att)
{
return (stristr(att, ".GIF") != NULL) || (stristr(att, ".JPG") != NULL) || (stristr(att, ".JPEG") != NULL)
|| (stristr(att, ".PNG") != NULL) || (stristr(att, ".SVG") != NULL);
}
/*------------------------------------------------------------------*/
void strip_html(char *s)
{
char *p;
while ((p = strchr(s, '<')) != NULL) {
if (strchr(p, '>'))
memmove(p, strchr(p, '>') + 1, strlen(strchr(p, '>') + 1) + 1);
else
*p = 0;
}
}
/*------------------------------------------------------------------*/
int line_break(char *str, char *encoding)
{
if (strieq(encoding, "plain") || strieq(encoding, "ELCode")) {
return str[0] == '\n';
}
// HTML encoding
if (strncmp(str, "
", 4) == 0 || strncmp(str, "
", 4) == 0 || strncmp(str, "
", 6) == 0)
return 1;
return 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 replace_inline_img(LOGBOOK * lbs, char *str)
{
char *p, *pn, *pa, old[256], link[256], base_url[256], domain[256];
int index;
p = str;
do {
p = strstr(p, "
')
pn++;
if (*pn == '>')
pn++;
retrieve_domain(domain, sizeof(domain));
sprintf(p, "
", index, domain);
memmove(p + strlen(p), pn, strlen(pn) + 1);
/* now change href to absolute link */
pa = p - 1;
while (pa > str && *pa != '<')
// search ''
pa--;
pn = strstr(pa, "href=");
if (pn && pn - pa < 10) {
strlcpy(old, pn + 6, sizeof(old));
if (strchr(old, '\"'))
*strchr(old, '\"') = 0;
compose_base_url(lbs, base_url, sizeof(base_url), FALSE);
strlcpy(link, base_url, sizeof(link));
strlcat(link, old, sizeof(link));
if (strchr(link, '?'))
*strchr(link, '?') = 0;
strsubst(pn + 6, TEXT_SIZE, old, link);
if (strlen(link) > strlen(old))
p += strlen(link) - strlen(old);
}
p++;
} else
p++;
}
} while (p != NULL);
}
/*------------------------------------------------------------------*/
void convert_elog_link(LOGBOOK * lbs, char *link, char *link_text, char *result, int absolute_link,
int message_id)
{
char str[256], base_url[256];
int i;
strlcpy(str, link, sizeof(str));
if (strchr(str, '/'))
*strchr(str, '/') = 0;
for (i = 0; i < (int) strlen(str); i++)
if (!isdigit(str[i]))
break;
if (i < (int) strlen(str)) {
/* if link contains reference to other logbook, put logbook explicitly */
if (absolute_link)
compose_base_url(NULL, base_url, sizeof(base_url), FALSE);
else
strcpy(base_url, "../");
sprintf(result, "elog:%s", base_url, link, link_text);
} else if (link[0] == '/') {
if (absolute_link)
compose_base_url(NULL, base_url, sizeof(base_url), FALSE);
else
base_url[0] = 0;
sprintf(result, "elog:%s", base_url, lbs->name_enc, message_id, link,
link_text);
} else {
if (absolute_link)
compose_base_url(lbs, base_url, sizeof(base_url), FALSE);
else
base_url[0] = 0;
sprintf(result, "elog:%s", base_url, link, link_text);
}
}
/*------------------------------------------------------------------*/
void rsputs(const char *str)
{
if (strlen_retbuf + (int) strlen(str) + 1 >= return_buffer_size) {
return_buffer = xrealloc(return_buffer, return_buffer_size + (int) strlen(str) + 100000);
memset(return_buffer + return_buffer_size, 0, (int) strlen(str) + 100000);
return_buffer_size += (int) strlen(str) + 100000;
}
strcpy(return_buffer + strlen_retbuf, str);
strlen_retbuf += strlen(str);
}
/*------------------------------------------------------------------*/
char *key_list[] = { "http://", "https://", "ftp://", "mailto:", "elog:", "file://", "" };
void rsputs2(LOGBOOK * lbs, int absolute_link, const char *str)
{
int i, j, k, l, n;
char *p, *pd, link[1000], link_text[1000];
if (strlen_retbuf + (int) (2 * strlen(str) + 1000) >= return_buffer_size) {
return_buffer = xrealloc(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; key_list[l][0]; l++) {
if (strncmp(str + i, key_list[l], strlen(key_list[l])) == 0) {
/* check for escape character */
if (i > 0 && *(str + i - 1) == '\\') {
j--;
*(return_buffer + j) = 0;
continue;
}
p = (char *) (str + i + strlen(key_list[l]));
i += strlen(key_list[l]);
for (k = 0; *p && strcspn(p, " \t\n\r({[)}]\"") && k < (int) sizeof(link); 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] == ',') {
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++;
memmove(p, pd + 1, strlen(pd + 1) + 1);
/* skip '' */
p = strchr(link, '\001');
if (p != NULL) {
pd = p;
while (*pd && *pd != '\002')
*p = *pd++;
memmove(p, pd + 1, strlen(pd + 1) + 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(key_list[l], "elog:") == 0) {
convert_elog_link(lbs, link, link_text, return_buffer + j, absolute_link, _current_message_id);
} else if (strcmp(key_list[l], "mailto:") == 0) {
sprintf(return_buffer + j, "%s", link, link_text);
} else {
sprintf(return_buffer + j, "%s", key_list[l]);
j += strlen(return_buffer + j);
strlen_retbuf = j;
/* link_text can contain special characters */
rsputs2(lbs, absolute_link, link_text);
j = strlen_retbuf;
sprintf(return_buffer + j, "");
}
j += strlen(return_buffer + j);
break;
}
}
if (!key_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 += 5;
break;
case '<':
strcat(return_buffer, "<");
j += 4;
break;
case '>':
strcat(return_buffer, ">");
j += 4;
break;
/* suppress escape character '\' in front of HTML or ELCode tag */
case '\\':
if (str[i + 1] != '<' && str[i + 1] != '[')
return_buffer[j++] = str[i];
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 rsputs3(const char *text)
{
int i;
char str[2];
str[1] = 0;
for (i = 0; i < (int) strlen(text); i++) {
switch (text[i]) {
case '<':
rsputs("<");
break;
case '>':
rsputs(">");
break;
case '&':
rsputs("&");
break;
case '\"':
rsputs(""");
break;
default:
str[0] = text[i];
rsputs(str);
}
}
}
/*------------------------------------------------------------------*/
typedef struct {
char *pattern;
char *subst;
} PATTERN_LIST;
PATTERN_LIST pattern_list[] = {
/* smileys */
{":))", "
"},
{":-))", "
"},
{":)", "
"},
{":-)", "
"},
{":(", "
"},
{":-(", "
"},
{";)", "
"},
{";-)", "
"},
{":d", "
"},
{"?-)", "
"},
{";(", "
"},
{";-(", "
"},
{":]", "
"},
{":-]", "
"},
{":o", "
"},
{":-o", "
"},
{"8-)", "
"},
{"8o", "
"},
{"x-(", "
"},
{":p", "
"},
{":-p", "
"},
/* formatting */
{"[b]", ""},
{"[/b]", ""},
{"[u]", ""},
{"[/u]", ""},
{"[i]", ""},
{"[/i]", ""},
{"[center]", ""},
{"[/center]", ""},
{"[color=", ""},
{"[/color]", ""},
{"[size=", ""},
{"[/size]", ""},
{"[font=", ""},
{"[/font]", ""},
{"\r\n[code]", ""},
{"[code]", ""},
{"[/code]\r\n", ""},
{"[/code]", ""},
{"\r\n[code1]", ""},
{"[code1]", ""},
{"[/code1]\r\n", ""},
{"[/code1]", ""},
/* lists */
{"[list]\r", ""},
{"[list]", ""},
{"[*]", "- "},
{"[/list]\r", "#>"}, // either
or
{"[/list]", "#>"},
{"[list=", ""},
/* headings */
{"[h1]", ""},
{"[/h1]", "
"},
{"[h2]", ""},
{"[/h2]", "
"},
{"[h3]", ""},
{"[/h3]", "
"},
/* URLs */
{"[url=", "%s"},
{"[url]", "%s"},
{"[/url]", ""},
{"[email]", "%s"},
{"[/email]", ""},
{"[img]", "
"},
{"[/img]", ""},
/* quote */
{"[quote=",
"
| %s: |
"},
{"[quote]",
"
\r\n"},
{"[/quote]", " |
\r\n"},
/* table */
{"[table]", ""},
{"[table ", "| "},
{"|-", " | | "},
{"|", " | "},
{"[/table]", " | "},
/* horizontal line */
{"[line]", " "},
/* anchor */
{"[anchor]", ""},
{"[/anchor]", ""},
{"", ""}
};
char
*email_quote_table =
"| %s: | ";
void rsputs_elcode(LOGBOOK * lbs, BOOL email_notify, const char *str)
{
int i, j, k, l, m, elcode_disabled, elcode_disabled1, escape_char, ordered_list, substituted, inside_table,
smileys_enabled;
char *p, *pd, link[1000], link_text[1000], tmp[1000], attrib[1000], hattrib[1000], value[1000],
subst[1000], base_url[256], param[256], *lstr, domain[256];
if (strlen_retbuf + (int) (2 * strlen(str) + 1000) >= return_buffer_size) {
return_buffer = xrealloc(return_buffer, return_buffer_size + 100000);
memset(return_buffer + return_buffer_size, 0, 100000);
return_buffer_size += 100000;
}
elcode_disabled = FALSE;
elcode_disabled1 = FALSE;
ordered_list = FALSE;
escape_char = FALSE;
smileys_enabled = TRUE;
inside_table = 0;
j = strlen_retbuf;
m = 0;
/* check for smileys */
if (getcfg(lbs->name, "Enable smileys", tmp, sizeof(tmp)) && atoi(tmp) == 0)
smileys_enabled = FALSE;
/* make lower case copy of str */
lstr = xmalloc(strlen(str) + 1);
for (pd = lstr, p = (char *) str; *p; p++, pd++)
*pd = tolower(*p);
*pd = 0;
for (i = 0; i < (int) strlen(str); i++) {
for (l = 0; key_list[l][0]; l++) {
if (strncmp(lstr + i, key_list[l], strlen(key_list[l])) == 0) {
/* check for escape character */
if (i > 0 && *(str + i - 1) == '\\') {
j--;
*(return_buffer + j) = 0;
continue;
}
p = (char *) (str + i + strlen(key_list[l]));
i += strlen(key_list[l]);
for (k = 0; *p && strcspn(p, " \t\n\r({[)}]\"") && k < (int) sizeof(link); 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] == ',') {
link[k - 1] = 0;
k--;
i--;
}
strlcpy(link_text, link, sizeof(link_text));
/* check if link contains coloring */
while ((p = strchr(link, '\001')) != NULL) {
/* skip everything between '<' and '>' */
pd = p;
while (*pd && *pd != '\002')
*p = *pd++;
memmove(p, pd + 1, strlen(pd + 1) + 1);
/* skip '' */
p = strchr(link, '\001');
if (p != NULL) {
pd = p;
while (*pd && *pd != '\002')
*p = *pd++;
memmove(p, pd + 1, strlen(pd + 1) + 1);
}
}
if (strcmp(key_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) && tmp[m] != '#') {
/* if link contains reference to other logbook, put logbook explicitly */
if (email_notify)
compose_base_url(NULL, base_url, sizeof(base_url), TRUE);
else
strcpy(base_url, "../");
sprintf(return_buffer + j, "elog:%s", base_url, link, link_text);
} else if (link[0] == '/') {
if (email_notify)
compose_base_url(NULL, base_url, sizeof(base_url), TRUE);
else
base_url[0] = 0;
sprintf(return_buffer + j, "elog:%s", base_url, lbs->name_enc,
_current_message_id, link, link_text);
} else {
if (email_notify)
compose_base_url(lbs, base_url, sizeof(base_url), TRUE);
else
base_url[0] = 0;
sprintf(return_buffer + j, "elog:%s", base_url, link, link_text);
}
} else if (strcmp(key_list[l], "mailto:") == 0) {
sprintf(return_buffer + j, "%s", link, link_text);
} else {
sprintf(return_buffer + j, "%s", key_list[l]);
j += strlen(return_buffer + j);
strlen_retbuf = j;
/* link_text can contain special characters */
rsputs2(lbs, email_notify, link_text);
j = strlen_retbuf;
sprintf(return_buffer + j, "");
}
j += strlen(return_buffer + j);
break;
}
}
if (key_list[l][0])
continue;
substituted = FALSE;
for (l = 0; pattern_list[l].pattern[0]; l++) {
if (strncmp(lstr + i, pattern_list[l].pattern, strlen(pattern_list[l].pattern)) == 0) {
if (stristr(pattern_list[l].pattern, "[/code]"))
elcode_disabled = FALSE;
if (stristr(pattern_list[l].pattern, "[/code1]"))
elcode_disabled1 = FALSE;
/* check for escape character */
if (i > 0 && str[i - 1] == '\\') {
j--;
strncpy(return_buffer + j, str + i, strlen(pattern_list[l].pattern));
j += strlen(pattern_list[l].pattern);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
substituted = TRUE;
break;
}
/* check for blank before smiley and if smileys are allowed */
if (l <= 20 &&
((str[i - 1] != ' ' && str[i - 1] != '\r' && str[i - 1] != '\n') ||
(smileys_enabled == FALSE))) {
strncpy(return_buffer + j, str + i, strlen(pattern_list[l].pattern));
j += strlen(pattern_list[l].pattern);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
substituted = TRUE;
break;
}
if (!elcode_disabled && !elcode_disabled1) {
substituted = TRUE;
if (stristr(pattern_list[l].pattern, "[list="))
ordered_list = TRUE;
if (stristr(pattern_list[l].pattern, "[table"))
inside_table++;
if (stristr(pattern_list[l].pattern, "[/table]"))
inside_table--;
if (stristr(pattern_list[l].pattern, "[quote")) {
if (pattern_list[l].pattern[strlen(pattern_list[l].pattern) - 1] == '=') {
i += strlen(pattern_list[l].pattern);
strextract(str + i, ']', attrib, sizeof(attrib));
i += strlen(attrib);
if (attrib[0] == '\"')
memmove(attrib, attrib + 1, strlen(attrib + 1) + 1);
if (attrib[strlen(attrib) - 1] == '\"')
attrib[strlen(attrib) - 1] = 0;
sprintf(value, loc("%s wrote"), attrib);
if (email_notify)
sprintf(return_buffer + j, email_quote_table, value);
else
sprintf(return_buffer + j, pattern_list[l].subst, value);
j += strlen(return_buffer + j);
} else {
if (email_notify)
sprintf(return_buffer + j, email_quote_table, loc("Quote"));
else
sprintf(return_buffer + j, pattern_list[l].subst, loc("Quote"));
j += strlen(return_buffer + j);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
}
}
else if (strstr(pattern_list[l].subst, "%#")) {
/* special substitutions */
if (pattern_list[l].pattern[strlen(pattern_list[l].pattern) - 1] == '=') {
i += strlen(pattern_list[l].pattern);
strextract(str + i, ']', attrib, sizeof(attrib));
i += strlen(attrib) + 1;
if (strncmp(attrib, "elog:", 5) == 0) { /* eval elog: */
strlcpy(tmp, attrib + 5, 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(hattrib, "../%s", attrib + 5);
else if (attrib[5] == '/')
sprintf(hattrib, "%d%s", _current_message_id, attrib + 5);
else
sprintf(hattrib, "%s", attrib + 5);
} else if (strstr(attrib, "://") == 0 && attrib[0] != '#') { /* add http:// if missing */
if (_ssl_flag)
sprintf(hattrib, "https://%s", attrib);
else
sprintf(hattrib, "http://%s", attrib);
} else
strlcpy(hattrib, attrib, sizeof(hattrib));
strextract(str + i, '[', value, sizeof(value));
i += strlen(value) - 1;
strlcpy(subst, pattern_list[l].subst, sizeof(subst));
*strchr(subst, '#') = 's';
sprintf(return_buffer + j, subst, hattrib, value);
j += strlen(return_buffer + j);
} else if (pattern_list[l].pattern[strlen(pattern_list[l].pattern) - 1] != '=') {
i += strlen(pattern_list[l].pattern);
strextract(str + i, '[', attrib, sizeof(attrib));
i += strlen(attrib) - 1;
strlcpy(hattrib, attrib, sizeof(hattrib));
/* replace elog:x/x for images */
if (strnieq(attrib, "elog:", 5)) {
if (email_notify) {
retrieve_domain(domain, sizeof(domain));
sprintf(hattrib, "cid:att%d@%s", m, domain);
} else {
if (email_notify)
compose_base_url(lbs, hattrib, sizeof(hattrib), TRUE);
else
hattrib[0] = 0;
if (attrib[5] == '/') {
if (_current_message_id == 0) {
sprintf(param, "attachment%d", atoi(attrib + 6) - 1);
if (isparam(param))
strlcat(hattrib, getparam(param), sizeof(hattrib));
} else
sprintf(hattrib + strlen(hattrib), "%d%s", _current_message_id, attrib + 5);
} else {
strlcat(hattrib, attrib + 5, sizeof(hattrib));
}
}
}
/* add http:// if missing */
else if ((!strnieq(attrib, "http://", 7) && !strnieq(attrib, "https://", 8)) &&
strstr(pattern_list[l].subst, "mailto") == NULL &&
strstr(pattern_list[l].subst, "img") == NULL &&
strncmp(pattern_list[l].subst, " ", sizeof(subst));
strsubst(subst, sizeof(subst), "%#", hattrib);
sprintf(return_buffer + j, subst, attrib);
j += strlen(return_buffer + j);
}
} else if (pattern_list[l].pattern[strlen(pattern_list[l].pattern) - 1] == '=') {
/* extract sting after '=' and put it into '%s' of subst */
i += strlen(pattern_list[l].pattern);
strextract(str + i, ']', attrib, sizeof(attrib));
i += strlen(attrib);
sprintf(return_buffer + j, pattern_list[l].subst, attrib);
j += strlen(return_buffer + j);
} else if (pattern_list[l].pattern[strlen(pattern_list[l].pattern) - 1] == ' ') {
/* extract sting after ' ' and put it into '%s' of subst */
i += strlen(pattern_list[l].pattern);
strextract(str + i, ']', attrib, sizeof(attrib));
i += strlen(attrib);
sprintf(return_buffer + j, pattern_list[l].subst, attrib);
j += strlen(return_buffer + j);
} else if (strncmp(pattern_list[l].pattern, "[/list]", 7) == 0) {
if (ordered_list)
strcpy(subst, "");
else
strcpy(subst, "");
ordered_list = FALSE;
strcpy(return_buffer + j, subst);
j += strlen(subst);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
} else if (strncmp(pattern_list[l].pattern, "|", 1) == 0) {
if (inside_table) {
strcpy(link, pattern_list[l].subst);
if (strstr(link, "%s")) {
strcpy(tmp, link);
if (email_notify)
compose_base_url(lbs, base_url, sizeof(base_url), TRUE);
else
base_url[0] = 0;
sprintf(link, tmp, base_url);
}
strcpy(return_buffer + j, link);
j += strlen(link);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
} else {
strcpy(return_buffer + j, pattern_list[l].pattern);
j += strlen(pattern_list[l].pattern);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
}
} else {
/* simple substitution */
strcpy(link, pattern_list[l].subst);
if (strstr(link, "%s")) {
strcpy(tmp, link);
if (email_notify)
compose_base_url(lbs, base_url, sizeof(base_url), TRUE);
else
base_url[0] = 0;
sprintf(link, tmp, base_url);
}
strcpy(return_buffer + j, link);
j += strlen(link);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
}
} // !elcode_disabled && !elcode_disabled1
else if (!elcode_disabled) {
substituted = TRUE;
/* simple substitution */
strcpy(link, pattern_list[l].subst);
if (strstr(link, "%s")) {
strcpy(tmp, link);
if (email_notify)
compose_base_url(lbs, base_url, sizeof(base_url), TRUE);
else
base_url[0] = 0;
sprintf(link, tmp, base_url);
}
strcpy(return_buffer + j, link);
j += strlen(link);
i += strlen(pattern_list[l].pattern) - 1; // 1 gets added in for loop...
}
if (stristr(pattern_list[l].pattern, "[code]"))
elcode_disabled = TRUE;
if (stristr(pattern_list[l].pattern, "[code1]"))
elcode_disabled1 = TRUE;
break;
}
}
/* don't output tags if already subsituted by HTML code */
if (substituted)
continue;
if (strnieq(str + i, " ", 4)) {
strcpy(return_buffer + j, " ");
j += 6;
i += 3;
} else
switch (str[i]) {
case '\r':
if (!elcode_disabled && !elcode_disabled1 && !inside_table) {
strcat(return_buffer, " \r\n");
j += 8;
} else {
strcat(return_buffer, "\r\n");
j += 2;
}
break;
case '\n':
break;
case '&':
strcat(return_buffer, "&");
j += 5;
break;
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];
}
}
xfree(lstr);
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) + 1 >= return_buffer_size) {
return_buffer = xrealloc(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()
{
#ifdef HAVE_SSL
if (_ssl_flag) {
SSL_write(_ssl_con, return_buffer, strlen_retbuf);
} else
#endif
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 (%lu bytes). Please increase TEXT_SIZE and recompile elogd\n",
(unsigned long) 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 (%lu bytes). Please increase CMD_SIZE and recompile elogd\n",
(unsigned long) 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 (%lu bytes).\n", (unsigned long) 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 (%lu bytes). Please increase NAME_LENGTH and recompile elogd\n",
param, (unsigned long) 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 && _param[i][0])
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;
if (strieq(param, "text"))
return _mtext[0] != 0;
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];
p = NULL;
if (strstr(str, "http://"))
p = str + 7;
if (strstr(str, "https://"))
p = str + 8;
if (p) {
while (*p && *p != '/')
p++;
if (*p == '/')
p++;
strcpy(str2, p);
strcpy(str, str2);
if (str[strlen(str) - 1] == '/')
str[strlen(str) - 1] = 0;
}
}
/*------------------------------------------------------------------*/
void extract_host(char *str)
{
char *p, *ph, str2[256];
p = NULL;
if (strstr(str, "http://"))
p = str + 7;
else if (strstr(str, "https://"))
p = str + 8;
if (p) {
ph = p;
while (*p && *p != '/' && *p != ':')
p++;
*p = 0;
strcpy(str2, ph);
strcpy(str, str2);
}
}
/*------------------------------------------------------------------*/
void compose_base_url(LOGBOOK * lbs, char *base_url, int size, BOOL email_notify)
/* return URL for elogd with optional logbook subdirectory */
{
if (email_notify)
if (getcfg(lbs->name, "Use Email URL", base_url, size))
return;
if (!getcfg("global", "URL", base_url, size)) {
if (referer[0]) {
/* get URL from referer */
strlcpy(base_url, referer, size);
if (strchr(base_url, '?'))
*strchr(base_url, '?') = 0;
if (strrchr(base_url, '/'))
*(strrchr(base_url, '/') + 1) = 0;
} else {
if (_ssl_flag)
strcpy(base_url, "https://");
else
strcpy(base_url, "http://");
if (elog_tcp_port == 80)
sprintf(base_url + strlen(base_url), "%s/", host_name);
else
sprintf(base_url + strlen(base_url), "%s:%d/", host_name, elog_tcp_port);
if (lbs) {
strlcat(base_url, lbs->name_enc, size);
strlcat(base_url, "/", size);
}
}
} else {
if (base_url[strlen(base_url) - 1] != '/')
strlcat(base_url, "/", size);
if (lbs) {
strlcat(base_url, lbs->name_enc, size);
strlcat(base_url, "/", size);
}
}
}
/*------------------------------------------------------------------*/
void set_location(LOGBOOK * lbs, char *rp)
{
char str[NAME_LENGTH], group[NAME_LENGTH], list[NAME_LENGTH], *p, rel_path[NAME_LENGTH];
int i;
/* remove any CR/LF from path */
strlcpy(rel_path, rp, sizeof(rel_path));
if (strchr(rel_path, '\r'))
*strchr(rel_path, '\r') = 0;
if (strchr(rel_path, '\n'))
*strchr(rel_path, '\n') = 0;
if (getcfg(lbs->name, "Relative redirect", str, sizeof(str)) && atoi(str) == 1) {
if (rel_path[0])
strlcpy(str, rel_path, sizeof(str));
else
strlcpy(str, ".", sizeof(str));
rsputs("Location: ");
rsputs(str);
} else {
/* Absolute redirect */
/* if path contains http(s), go directly there */
if (strncmp(rel_path, "http://", 7) == 0) {
rsputs("Location: ");
rsputs(rel_path);
} else if (strncmp(rel_path, "https://", 8) == 0) {
rsputs("Location: ");
rsputs(rel_path);
} else {
/* check for URL options */
str[0] = 0;
if (lbs)
getcfg(lbs->name, "URL", str, sizeof(str));
else
getcfg("global", "URL", str, sizeof(str));
if (str[0] == 0) {
/* get redirection from referer and host */
if (referer[0]) {
strlcpy(str, referer, sizeof(str));
/* strip any parameter */
if (strchr(str, '?'))
*strchr(str, '?') = 0;
/* strip rightmost '/' */
if (str[strlen(str) - 1] == '/')
str[strlen(str) - 1] = 0;
/* extract last subdir */
p = str + strlen(str);
while (p > str && *p != '/')
p--;
if (*p == '/')
p++;
/* if last subdir equals any logbook name, strip it */
for (i = 0; lb_list[i].name[0]; i++)
if (stricmp(p, lb_list[i].name_enc) == 0) {
*p = 0;
break;
}
/* if last subdir equals any group, strip it */
sprintf(group, "Group %s", p);
if (getcfg("global", group, list, sizeof(list)))
*p = 0;
/* if last subdir equals any top group, strip it */
sprintf(group, "Top group %s", p);
if (getcfg("global", group, list, sizeof(list)))
*p = 0;
} else {
/* assemble absolute path from host name and port */
if (_ssl_flag)
sprintf(str, "https://%s", http_host);
else
sprintf(str, "http://%s", http_host);
if (elog_tcp_port != 80 && strchr(str, ':') == NULL)
sprintf(str + strlen(str), ":%d", elog_tcp_port);
strlcat(str, "/", sizeof(str));
}
/* add trailing '/' if not present */
if (str[strlen(str) - 1] != '/')
strlcat(str, "/", sizeof(str));
/* add top group if existing and not logbook */
if (!lbs && getcfg_topgroup()) {
strlcat(str, getcfg_topgroup(), sizeof(str));
strlcat(str, "/", sizeof(str));
}
if (strncmp(rel_path, "../", 3) == 0)
strlcat(str, rel_path + 3, sizeof(str));
else if (strcmp(rel_path, ".") == 0) {
if (lbs)
strlcat(str, lbs->name_enc, sizeof(str));
} else if (rel_path[0] == '/')
strlcat(str, rel_path + 1, sizeof(str));
else {
if (lbs) {
strlcat(str, lbs->name_enc, sizeof(str));
strlcat(str, "/", sizeof(str));
strlcat(str, rel_path, sizeof(str));
} else
strlcat(str, rel_path, sizeof(str));
}
rsputs("Location: ");
rsputs(str);
} else {
/* use redirection via URL */
/* 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")) {
if (_ssl_flag)
strlcpy(str, "https://localhost", sizeof(str));
else
strlcpy(str, "http://localhost", sizeof(str));
if (elog_tcp_port != 80)
sprintf(str + strlen(str), ":%d", elog_tcp_port);
strlcat(str, "/", sizeof(str));
}
/* add trailing '/' if not present */
if (str[strlen(str) - 1] != '/')
strlcat(str, "/", sizeof(str));
/* add top group if existing and not logbook */
if (!lbs && getcfg_topgroup()) {
strlcat(str, getcfg_topgroup(), sizeof(str));
strlcat(str, "/", sizeof(str));
}
if (strncmp(rel_path, "../", 3) == 0)
strlcat(str, rel_path + 3, sizeof(str));
else if (strcmp(rel_path, ".") == 0) {
if (lbs)
strlcat(str, lbs->name_enc, sizeof(str));
} else if (rel_path[0] == '/')
strlcat(str, rel_path + 1, sizeof(str));
else {
if (lbs) {
strlcat(str, lbs->name_enc, sizeof(str));
strlcat(str, "/", sizeof(str));
strlcat(str, rel_path, sizeof(str));
} else
strlcat(str, rel_path, sizeof(str));
}
rsputs("Location: ");
rsputs(str);
}
}
}
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])
strlcpy(str, redir, sizeof(str));
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");
if (value != NULL)
rsprintf("Set-Cookie: %s=%s;", name, value);
else
rsprintf("Set-Cookie: %s;", name);
/* add path */
if (global) {
/* path for all logbooks */
if (getcfg(lb_name, "URL", str, sizeof(str))) {
extract_path(str);
url_encode(str, sizeof(str));
rsprintf(" path=/%s;", str);
} else
rsprintf(" path=/;");
} else {
/* path for individual logbook */
if (getcfg(lb_name, "URL", str, sizeof(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 != NULL && value[0] == 0)
exp = -24;
/* add expriation date */
if (exp != 0 && exp < 100000) {
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-%d\r\n", VERSION, atoi(svn_revision + 13));
if (keep_alive) {
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, BOOL ignore_quotes)
/* 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 == '"' && !ignore_quotes) {
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;
break;
}
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], str2[NAME_LENGTH], type[NAME_LENGTH],
tmp_list[MAX_N_ATTR][NAME_LENGTH];
int i, j, n, m, n_options;
if (getcfg(logbook, "Attributes", list, sizeof(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, ",", FALSE);
/* check for forbidden attributes */
for (i = 0; i < n; i++) {
if (strieq(attr_list[i], "id") ||
strieq(attr_list[i], "text") ||
strieq(attr_list[i], "date") ||
strieq(attr_list[i], "encoding") ||
strieq(attr_list[i], "reply to") ||
strieq(attr_list[i], "locked by") ||
strieq(attr_list[i], "in reply to") || strieq(attr_list[i], "attachment")) {
sprintf(str, loc("Attribute \"%s\" is not allowed in config file"), attr_list[i]);
show_error(str);
return -1;
}
}
/* get options lists for attributes */
memset(attr_options, 0, sizeof(attr_options));
for (i = 0; i < n; i++) {
n_options = 0;
sprintf(str, "Options %s", attr_list[i]);
if (getcfg(logbook, str, list, sizeof(list)))
n_options = strbreak(list, attr_options[i], MAX_N_LIST, ",", FALSE);
sprintf(str, "MOptions %s", attr_list[i]);
if (getcfg(logbook, str, list, sizeof(list))) {
n_options = strbreak(list, attr_options[i], MAX_N_LIST, ",", FALSE);
attr_flags[i] |= AF_MULTI;
}
sprintf(str, "ROptions %s", attr_list[i]);
if (getcfg(logbook, str, list, sizeof(list))) {
n_options = strbreak(list, attr_options[i], MAX_N_LIST, ",", FALSE);
attr_flags[i] |= AF_RADIO;
}
sprintf(str, "IOptions %s", attr_list[i]);
if (getcfg(logbook, str, list, sizeof(list))) {
n_options = strbreak(list, attr_options[i], MAX_N_LIST, ",", FALSE);
attr_flags[i] |= AF_ICON;
}
sprintf(str2, "Sort Attribute Options %s", attr_list[i]);
if (n_options && getcfg(logbook, str2, str, sizeof(str)) && atoi(str) == 1) {
qsort(attr_options[i], n_options, NAME_LENGTH, ascii_compare2);
}
}
/* check if attribute required */
getcfg(logbook, "Required Attributes", list, sizeof(list));
m = strbreak(list, tmp_list, MAX_N_ATTR, ",", FALSE);
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, sizeof(list));
m = strbreak(list, tmp_list, MAX_N_ATTR, ",", FALSE);
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, sizeof(list));
m = strbreak(list, tmp_list, MAX_N_ATTR, ",", FALSE);
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, sizeof(list));
m = strbreak(list, tmp_list, MAX_N_ATTR, ",", FALSE);
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, sizeof(list));
m = strbreak(list, tmp_list, MAX_N_ATTR, ",", FALSE);
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, sizeof(type))) {
if (strieq(type, "date"))
attr_flags[i] |= AF_DATE;
if (strieq(type, "datetime"))
attr_flags[i] |= AF_DATETIME;
if (strieq(type, "time"))
attr_flags[i] |= AF_TIME;
if (strieq(type, "numeric"))
attr_flags[i] |= AF_NUMERIC;
if (strieq(type, "userlist"))
attr_flags[i] |= AF_USERLIST;
if (strieq(type, "muserlist"))
attr_flags[i] |= AF_MUSERLIST;
if (strieq(type, "useremail"))
attr_flags[i] |= AF_USEREMAIL;
if (strieq(type, "museremail"))
attr_flags[i] |= AF_MUSEREMAIL;
}
}
} 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(LOGBOOK * lbs, BOOL expires, char *cookie)
{
char str[256];
rsprintf("HTTP/1.1 200 Document follows\r\n");
rsprintf("Server: ELOG HTTP %s-%d\r\n", VERSION, atoi(svn_revision + 13));
if (getcfg("global", "charset", str, sizeof(str)))
rsprintf("Content-Type: text/html;charset=%s\r\n", str);
else
rsprintf("Content-Type: text/html;charset=%s\r\n", DEFAULT_HTTP_CHARSET);
if (cookie && cookie[0])
set_cookie(lbs, cookie, NULL, FALSE, "99999"); /* ten years by default */
if (keep_alive) {
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-%d\r\n", VERSION, atoi(svn_revision + 13));
rsprintf("Accept-Ranges: bytes\r\n");
if (keep_alive) {
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, BOOL rss_feed, char *cookie,
int absolute_link, int refresh)
{
int i, n;
char css[1000], str[1000], media[1000];
char css_list[MAX_N_LIST][NAME_LENGTH];
show_http_header(lbs, expires, cookie);
/* DOCTYPE */
rsprintf("\n");
/* this code would be for XML files...
rsprintf("\n");
rsprintf("\n");
*/
/* page title */
rsprintf("\n");
rsprintf("\n");
if (refresh)
rsprintf("\n", refresh);
rsprintf("%s\n", title);
/* Cascading Style Sheet */
if (absolute_link)
compose_base_url(lbs, css, sizeof(css), FALSE);
else
css[0] = 0;
if (lbs != NULL && getcfg(lbs->name, "CSS", str, sizeof(str)))
strlcat(css, str, sizeof(css));
else if (lbs == NULL && getcfg("global", "CSS", str, sizeof(str)))
strlcat(css, str, sizeof(css));
else
strlcat(css, "default.css", sizeof(css));
if (strchr(css, ',')) {
n = strbreak(css, css_list, MAX_N_LIST, ",", FALSE);
for (i = 0; i < n; i++) {
strlcpy(str, css_list[i], sizeof(str));
if (strchr(str, '&')) {
strlcpy(media, strchr(str, '&') + 1, sizeof(media));
*strchr(str, '&') = 0;
rsprintf("\n", str, media);
}
}
} else
rsprintf("\n", css);
rsprintf("\n");
rsprintf("\n");
if (rss_feed) {
rsprintf("name);
rsprintf("href=\"elog.rdf\" />\n");
}
if (close_head)
rsprintf("\n");
}
void show_browser(char *browser)
{
if (stristr(browser, "opera"))
rsprintf("var browser = \"Opera\";\n");
else if (stristr(browser, "konqueror"))
rsprintf("var browser = \"Konqueror\";\n");
else if (stristr(browser, "Safari"))
rsprintf("var browser = \"Safari\";\n");
else if (stristr(browser, "MSIE"))
rsprintf("var browser = \"MSIE\";\n");
else if (stristr(browser, "Mozilla"))
rsprintf("var browser = \"Mozilla\";\n");
else
rsprintf("var browser = \"Other\";\n");
}
void show_standard_header(LOGBOOK * lbs, BOOL expires, char *title, char *path, BOOL rss_feed, char *cookie,
char *script, int refresh)
{
if (script) {
show_html_header(lbs, expires, title, FALSE, rss_feed, cookie, FALSE, refresh);
rsprintf("\n");
rsprintf("\n\n");
rsprintf("\n");
} else
show_html_header(lbs, expires, title, TRUE, rss_feed, cookie, FALSE, refresh);
if (script)
rsprintf("\n", script);
else
rsprintf("\n");
show_top_text(lbs);
if (path && path[0])
rsprintf(" |
|