/*
Copyright (C) 1999-2004 IC & S dbmail@ic-s.nl
Copyright (c) 2005-2006 NFG Net Facilities Group BV support@nfg.nl
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: misc.c 2209 2006-07-25 08:22:29Z paul $
*
* Miscelaneous functions */
#include "dbmail.h"
const char AcceptedMailboxnameChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789-=/ _.&,+@()[]'";
/**
* abbreviated names of the months
*/
const char *month_desc[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/* returned by date_sql2imap() */
#define IMAP_STANDARD_DATE "03-Nov-1979 00:00:00 +0000"
char _imapdate[IMAP_INTERNALDATE_LEN] = IMAP_STANDARD_DATE;
/* returned by date_imap2sql() */
#define SQL_STANDARD_DATE "1979-11-03 00:00:00"
char _sqldate[SQL_INTERNALDATE_LEN + 1] = SQL_STANDARD_DATE;
const int month_len[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
#undef max
#define max(x,y) ( (x) > (y) ? (x) : (y) )
/* only locally used */
typedef struct {
GTree *tree;
GList *list;
int condition;
} tree_merger_t;
int drop_privileges(char *newuser, char *newgroup)
{
/* will drop running program's priviledges to newuser and newgroup */
struct passwd *pwd;
struct group *grp;
grp = getgrnam(newgroup);
if (grp == NULL) {
trace(TRACE_ERROR, "%s,%s: could not find group %s\n",
__FILE__, __func__, newgroup);
return -1;
}
pwd = getpwnam(newuser);
if (pwd == NULL) {
trace(TRACE_ERROR, "%s,%s: could not find user %s\n",
__FILE__, __func__, newuser);
return -1;
}
if (setgid(grp->gr_gid) != 0) {
trace(TRACE_ERROR, "%s,%s: could not set gid to %s\n",
__FILE__, __func__, newgroup);
return -1;
}
if (setuid(pwd->pw_uid) != 0) {
trace(TRACE_ERROR, "%s,%s: could not set uid to %s\n",
__FILE__, __func__, newuser);
return -1;
}
return 0;
}
void create_unique_id(char *target, u64_t message_idnr)
{
char *a_message_idnr, *a_rand;
char *md5_str;
a_message_idnr = g_strdup_printf("%llu",message_idnr);
a_rand = g_strdup_printf("%d",rand());
if (message_idnr != 0)
snprintf(target, UID_SIZE, "%s:%s",
a_message_idnr, a_rand);
else
snprintf(target, UID_SIZE, "%s", a_rand);
md5_str = dm_md5((unsigned char *)target);
snprintf(target, UID_SIZE, "%s", md5_str);
trace(TRACE_DEBUG, "%s,%s: created: %s", __FILE__, __func__,
target);
dm_free(md5_str);
g_free(a_message_idnr);
g_free(a_rand);
}
void create_current_timestring(timestring_t * timestring)
{
time_t td;
struct tm tm;
if (time(&td) == -1)
trace(TRACE_FATAL, "%s,%s: error getting time from OS",
__FILE__, __func__);
tm = *localtime(&td); /* get components */
strftime((char *) timestring, sizeof(timestring_t),
"%Y-%m-%d %H:%M:%S", &tm);
}
char *mailbox_add_namespace(const char *mailbox_name, u64_t owner_idnr,
u64_t user_idnr)
{
char *fq;
char *owner;
GString *t;
if (mailbox_name == NULL) {
trace(TRACE_ERROR, "%s,%s: error, mailbox_name is NULL.",
__FILE__, __func__);
return NULL;
}
if (user_idnr == owner_idnr)
/* mailbox owned by current user */
return g_strdup(mailbox_name);
/* else */
if ((owner = auth_get_userid(owner_idnr))==NULL)
return NULL;
t = g_string_new("");
if (strcmp(owner, PUBLIC_FOLDER_USER) == 0)
g_string_printf(t, "%s%s%s", NAMESPACE_PUBLIC, MAILBOX_SEPARATOR, mailbox_name);
else
g_string_printf(t, "%s%s%s%s%s", NAMESPACE_USER, MAILBOX_SEPARATOR, owner,
MAILBOX_SEPARATOR, mailbox_name);
dm_free(owner);
fq = t->str;
g_string_free(t,FALSE);
return fq;
}
const char *mailbox_remove_namespace(const char *fq_name)
{
char *temp;
// i.e. '#Users/someuser/foldername'
if (strcmp(fq_name, NAMESPACE_USER) == 0) {
temp = strstr(fq_name, MAILBOX_SEPARATOR);
if (temp == NULL || strlen(temp) <= 1) {
trace(TRACE_ERROR, "%s,%s illegal mailbox name",
__FILE__, __func__);
return NULL;
}
temp = strstr(&temp[1], MAILBOX_SEPARATOR);
if (temp == NULL || strlen(temp) <= 1) {
trace(TRACE_ERROR, "%s,%s illegal mailbox name",
__FILE__, __func__);
return NULL;
}
return &temp[1];
}
// i.e. '#Public/foldername'
if (strcmp(fq_name, NAMESPACE_PUBLIC) == 0) {
temp = strstr(fq_name, MAILBOX_SEPARATOR);
if (temp == NULL || strlen(temp) <= 1) {
trace(TRACE_ERROR, "%s,%s illegal mailbox name",
__FILE__, __func__);
return NULL;
}
return &temp[1];
}
return fq_name;
}
int ci_write(FILE * fd, char * msg, ...)
{
va_list ap;
va_start(ap, msg);
if (feof(fd) || vfprintf(fd,msg,ap) < 0 || fflush(fd) < 0) {
va_end(ap);
return -1;
}
va_end(ap);
return 0;
}
/* Return 0 is all's well. Returns something else if not... */
int read_from_stream(FILE * instream, char **m_buf, size_t maxlen)
{
size_t f_len = 0;
size_t f_pos = 0;
char *tmp_buf = NULL;
char *f_buf = NULL;
/* Allocate a zero length string on length 0. */
if (maxlen < 1) {
*m_buf = dm_strdup("");
return 0;
}
tmp_buf = dm_malloc(sizeof(char) * (f_len += 512));
if (tmp_buf != NULL)
f_buf = tmp_buf;
else
return -2;
/* Shouldn't this also check for ferror() or feof() ?? */
while (f_pos < maxlen) {
if (f_pos + 1 >= f_len) {
/* Per suggestion of my CS instructor, double the
* buffer every time it is too small. This yields
* a logarithmic number of reallocations. */
tmp_buf =
dm_realloc(f_buf, sizeof(char) * (f_len *= 2));
if (tmp_buf != NULL)
f_buf = tmp_buf;
else
return -2;
}
f_buf[f_pos] = fgetc(instream);
f_pos++;
}
if (f_pos)
f_buf[f_pos] = '\0';
*m_buf = f_buf;
return 0;
}
/* Finds what lurks between two bounding symbols.
* Allocates and fills retchar with the string.
*
* Return values are:
* 0 on success (found and allocated)
* -1 on failure (not found)
* -2 on memory error (found but allocation failed)
*
* The caller is responsible for free()ing *retchar.
* */
int find_bounded(const char * const value, char left, char right,
char **retchar, size_t * retsize, size_t * retlast)
{
char *tmpleft;
char *tmpright;
size_t tmplen;
tmpleft = (char *)value;
tmpright = (char *)(value + strlen(value));
while (tmpleft[0] != left && tmpleft < tmpright)
tmpleft++;
while (tmpright[0] != right && tmpright > tmpleft)
tmpright--;
if (tmpleft[0] != left || tmpright[0] != right) {
trace(TRACE_INFO,
"%s, %s: Found nothing between '%c' and '%c'",
__FILE__, __func__, left, right);
*retchar = NULL;
*retsize = 0;
*retlast = 0;
return -1;
} else {
/* Step left up to skip the actual left thinger */
if (tmpright != tmpleft)
tmpleft++;
tmplen = tmpright - tmpleft;
*retchar = dm_malloc(sizeof(char) * (tmplen + 1));
if (*retchar == NULL) {
*retchar = NULL;
*retsize = 0;
*retlast = 0;
trace(TRACE_INFO,
"%s, %s: Found [%s] of length [%zd] between '%c' and '%c' so next skip [%zd]",
__FILE__, __func__, *retchar, *retsize,
left, right, *retlast);
return -2;
}
strncpy(*retchar, tmpleft, tmplen);
(*retchar)[tmplen] = '\0';
*retsize = tmplen;
*retlast = tmpright - value;
trace(TRACE_INFO,
"%s, %s: Found [%s] of length [%zd] between '%c' and '%c' so next skip [%zd]",
__FILE__, __func__, *retchar, *retsize, left,
right, *retlast);
return 0;
}
}
int zap_between(const char * const instring, signed char left, signed char right,
char **outstring, size_t *outlen, size_t *zaplen)
{
char *start, *end;
char *incopy = g_strdup(instring);
int clipleft = 0, clipright = 0;
if (!incopy)
return -2;
// Should we clip the left char, too?
if (left < 0) {
left = 0 - left;
clipleft = 1;
}
// Should we clip the right char, too?
if (right < 0) {
right = 0 - right;
clipright = 1;
}
start = strchr(incopy, left);
end = strrchr(incopy, right);
if (!start || !end) {
g_free(incopy);
return -1;
}
if (!clipleft) start++;
if (clipright) end++;
memmove(start, end, strlen(end)+1);
if (outstring)
*outstring = incopy;
if (outlen)
*outlen = strlen(incopy);
if (zaplen)
*zaplen = (end - start);
return 0;
}
/*
*
*
* Some basic string handling utilities
*
*
*
*/
GString * g_list_join(GList * list, const gchar * sep)
{
GString *string = g_string_new("");
if (sep == NULL)
sep="";
if (list == NULL)
return string;
list = g_list_first(list);
string = g_string_append(string, (gchar *)list->data);
while((list = g_list_next(list))) {
string = g_string_append(string,sep);
string = g_string_append(string,(gchar *)list->data);
if (! g_list_next(list))
break;
}
return string;
}
GList * g_string_split(GString * string, const gchar * sep)
{
GList * list = NULL;
char **array;
int i, len = 0;
if (string->len == 0)
return NULL;
array = (char **)g_strsplit((const gchar *)string->str, sep, 0);
while(array[len++]);
len--;
for (i=0; i<len; i++)
list = g_list_append(list,g_strdup(array[i]));
g_strfreev(array);
return list;
}
/*
* append a formatted string to a GList
*/
GList * g_list_append_printf(GList * list, char * format, ...)
{
va_list argp;
va_start(argp, format);
return g_list_append(list, g_strdup_vprintf(format, argp));
}
char * g_strcasestr(const char *haystack, const char *needle)
{
// Like strstr, but case insensitive.
size_t n = strlen(needle);
for (; *haystack; haystack++) {
if (g_ascii_strncasecmp(haystack, needle, n) == 0)
return (char *)haystack;
}
return NULL;
}
/*
* return newly allocated escaped strings
*/
char * dm_stresc(const char * from)
{
return dm_strnesc(from, strlen(from));
}
/*
* return newly allocated sql-escaped string with
* a maximum length of len
*/
char * dm_strnesc(const char * from, size_t len)
{
char *to;
assert(from);
len = min(strlen(from),len);
to = g_new0(char, (len + 1) * 2 + 1);
db_escape_string(to, from, len);
return to;
}
/*
*
* replace tabs with spaces and all multi-spaces with single spaces
*
*/
void dm_pack_spaces(char *in)
{
char *tmp, *saved;
/* replace tabs with spaces */
g_strdelimit(in,"\t",' ');
/* replace all multi-spaces with single spaces */
tmp = g_strdup(in);
saved = tmp;
while(*tmp) {
if ((*tmp == ' ') && (*(tmp+1) == ' ')) {
tmp++;
} else {
*in++=*tmp++;
}
}
g_free(saved);
*in='\0';
}
/*
* base-subject
*
*/
static void _strip_blob_prefix(char *subject)
{
char *tmp = g_strdup(subject);
char *saved = tmp;
if (*tmp == '[') {
while (*tmp != '\0' && *tmp != ']')
tmp++;
if (*tmp != ']') {
g_free(saved);
return;
}
g_strstrip(++tmp); // skip ']'
if (strlen(tmp) > 0)
strncpy(subject,tmp,strlen(tmp)+1);
}
g_free(saved);
return;
}
static void _strip_refwd(char *subject)
{
char *tmp, *saved;
if (! (strncasecmp(subject,"re",2)==0 || strncasecmp(subject,"fw",2)==0))
return;
tmp = g_strdup(subject);
saved = tmp;
if (strncasecmp(tmp,"fwd",3)==0)
tmp+=3;
else if ((strncasecmp(tmp,"re",2)==0) || (strncasecmp(tmp,"fw",2)==0))
tmp+=2;
g_strstrip(tmp);
if (strlen(tmp) > 0)
_strip_blob_prefix(tmp);
if (*tmp!=':') {
g_free(saved);
return;
}
g_strstrip(++tmp); // skip ':'
if (strlen(tmp) > 0)
strncpy(subject,tmp,strlen(tmp)+1);
g_free(saved);
}
static void _strip_sub_leader(char *subject)
{
unsigned len;
/* strip blobs prefixes */
while (1==1) {
len = strlen(subject);
_strip_blob_prefix(subject);
if (strlen(subject)==len)
break;
}
/* strip refwd prefixes */
_strip_refwd(subject);
}
void dm_base_subject(char *subject)
{
unsigned offset, len, olen;
char *tmp, *saved, *recoded;
tmp = g_mime_utils_header_decode_text((unsigned char *)subject);
saved = tmp;
dm_pack_spaces(tmp);
g_strstrip(tmp);
while (1==1) {
olen = strlen(tmp);
while (g_str_has_suffix(tmp,"(fwd)")) {
offset = strlen(tmp) - 5;
tmp[offset] = '\0';
g_strstrip(tmp);
}
while (1==1) {
len = strlen(tmp);
_strip_sub_leader(tmp);
if (strlen(tmp)==len)
break;
}
if (g_str_has_suffix(tmp,"]") && strncasecmp(tmp,"[fwd:",5)==0 ) {
offset=strlen(tmp)-1;
tmp[offset]='\0';
tmp+=5;
g_strstrip(tmp);
}
while (g_str_has_prefix(tmp,":") && (strlen(tmp) > 1))
g_strstrip(++tmp);
if (strlen(tmp)==olen)
break;
}
recoded = g_mime_utils_header_encode_text((unsigned char *)tmp);
strncpy(subject,recoded,strlen(subject)+1);
g_free(recoded);
g_free(saved);
}
/*
* \brief listexpression match for imap (rfc2060)
* \param p pattern
* \param s string to search
* \param x separator string ("." or "/"- multichar okay; e.g. "Ï€" would work f
* you can find a IMAP client that read rfc2060)
* \param flags presently only LISTEX_NOCASE -- if you want case-insensitive
* "folders"
* \return 1 indicates a match
*/
#define LISTEX_NOCASE 1
int listex_match(const char *p, const char *s,
const char *x, int flags)
{
int i, p8;
p8=0;
while (*p) {
if (!p8 && *p == '%') {
p++;
while (*s) {
for (i = 0; x[i] && x[i] == s[i]; i++);
if (! x[i]) {
s += i;
break;
}
s++;
}
/* %. */
for (i = 0; x[i] && x[i] == p[i]; i++);
if (! x[i]) p += i;
if (*s || *p) return 0;
return 1;
}
if (!p8 && *p == '*') {
/* use recursive for synchronize */
p++;
if (!(*p)) return 1;
while (*s) {
if (listex_match(p,s,x,flags)) return 1;
s++;
}
return 0;
}
if (!p8 && *p == *x) {
for (i = 0; x[i] && p[i] == x[i] && p[i] == s[i]; i++);
if (! x[i]) {
p += i; s += i;
continue; /* sync'd */
}
/* fall; try regular search */
}
if ((flags & LISTEX_NOCASE && tolower(((unsigned int)*p))
== tolower(((unsigned int)*s)))
|| (*p == *s)) {
p8=(((unsigned char)*p) > 0xC0);
p++; s++;
} else {
/* failed */
return 0;
}
}
if (*p || *s) return 0;
return 1;
}
u64_t dm_getguid(unsigned int serverid)
{
char s[30];
struct timeval tv;
assert((int)serverid >= 0);
if (gettimeofday(&tv,NULL))
return 0;
snprintf(s,30,"%ld%06ld%02d", tv.tv_sec, tv.tv_usec,serverid);
return (u64_t)strtoll(s,NULL,10);
}
sa_family_t dm_get_client_sockaddr(clientinfo_t *ci, struct sockaddr *saddr)
{
int maxsocklen = 128; /* ref. UNP */
union {
struct sockaddr sa;
char data[maxsocklen];
} un;
socklen_t len;
len = maxsocklen;
if (getsockname(fileno(ci->tx), (struct sockaddr *)un.data, &len) < 0)
return (sa_family_t) -1;
memcpy(saddr, &un.sa, sizeof(un.sa));
return (un.sa.sa_family);
}
int dm_sock_score(const char *base, const char *test)
{
struct cidrfilter *basefilter, *testfilter;
int result = 0;
char *t;
t = strstr(base,"unix:");
if (t==base) {
base = strstr(base,":");
test = strstr(test,":");
return (fnmatch(base,test,0) ? 0 : 1);
}
t = strstr(base,"inet:");
if (t!=base)
return 0;
if (! test)
return 0;
basefilter = cidr_new(base);
testfilter = cidr_new(test);
if (strlen(test)==0) {
result = 32;
} else if (basefilter && testfilter) {
result = cidr_match(basefilter,testfilter);
}
cidr_free(basefilter);
cidr_free(testfilter);
trace(TRACE_DEBUG, "%s,%s: base[%s] test[%s] => [%d]",
__FILE__, __func__, base, test, result);
return result;
}
static int socket_match(const char *base, const char *test)
{
return (dm_sock_score(base,test) ? 0 : 1);
}
int dm_sock_compare(const char *clientsock, const char *sock_allow, const char *sock_deny)
{
int result;
assert(clientsock);
if ( (strlen(sock_allow) == 0) && (strlen(sock_deny) == 0) ) {
result = DM_SUCCESS;
} else if (strlen(sock_deny) > 0 && socket_match(sock_deny, clientsock)==0) {
result = DM_EGENERAL;
} else if (strlen(sock_allow) > 0 && socket_match(sock_allow, clientsock)==0) {
result = DM_SUCCESS;
} else {
result = DM_EGENERAL;
}
trace(TRACE_DEBUG, "%s,%s: clientsock [%s] sock_allow[%s], sock_deny [%s] => [%d]",
__FILE__, __func__, clientsock, sock_allow, sock_deny, result);
return result;
}
/* dm_valid_format
* check if str is a valid format string containing a single "%s" for use in
* printf style calls
* \return 1 format is invalid
* \return 0 format is valid
*/
int dm_valid_format(const char *str)
{
char *left, *right;
left = index(str,'%');
right = rindex(str,'%');
if (! (left && right && left==right))
return DM_EGENERAL;
if (*(left+1) != 's')
return DM_EGENERAL;
return DM_SUCCESS;
}
/*
* checkmailboxname()
*
* performs a check to see if the mailboxname is valid
* returns 0 if invalid, 1 otherwise
*/
int checkmailboxname(const char *s)
{
int i;
if (strlen(s) == 0)
return 0; /* empty name is not valid */
if (strlen(s) >= IMAP_MAX_MAILBOX_NAMELEN)
return 0; /* a too large string is not valid */
/* check for invalid characters */
for (i = 0; s[i]; i++) {
if (!strchr(AcceptedMailboxnameChars, s[i])) {
/* dirty hack to allow namespaces to function */
if (i == 0 && s[0] == '#')
continue;
/* wrong char found */
return 0;
}
}
/* check for double '/' */
for (i = 1; s[i]; i++) {
if (s[i] == '/' && s[i - 1] == '/')
return 0;
}
/* check if the name consists of a single '/' */
if (strlen(s) == 1 && s[0] == '/')
return 0;
return 1;
}
/*
* check_date()
*
* checks a date for IMAP-date validity:
* dd-MMM-yyyy
* 01234567890
* month three-letter specifier
*/
int check_date(const char *date)
{
char sub[4];
int days, i, j;
if (strlen(date) != strlen("01-Jan-1970")
&& strlen(date) != strlen("1-Jan-1970"))
return 0;
j = (strlen(date) == strlen("1-Jan-1970")) ? 1 : 0;
if (date[2 - j] != '-' || date[6 - j] != '-')
return 0;
days = strtoul(date, NULL, 10);
strncpy(sub, &date[3 - j], 3);
sub[3] = 0;
for (i = 0; i < 12; i++) {
if (strcasecmp(month_desc[i], sub) == 0)
break;
}
if (i >= 12 || days > month_len[i])
return 0;
for (i = 7; i < 11; i++)
if (!isdigit(date[i - j]))
return 0;
return 1;
}
/*
* check_msg_set()
*
* checks if s represents a valid message set
*/
int check_msg_set(const char *s)
{
int i, indigit=0, result = 1;
if (!s || (!isdigit(s[0]) && s[0]!= '*') )
return 0;
for (i = 0; s[i]; i++) {
if (isdigit(s[i]) || s[i]=='*')
indigit = 1;
else if (s[i] == ',') {
if (!indigit) {
result = 0;
break;
}
indigit = 0;
} else if (s[i] == ':') {
if (!indigit) {
result = 0;
break;
}
indigit = 0;
} else {
result = 0;
break;
}
}
trace(TRACE_DEBUG, "%s,%s: [%s] [%s]", __FILE__, __func__, s, result ? "ok" : "fail" );
return result;
}
/*
* convert a mySQL date (yyyy-mm-dd hh:mm:ss) to a valid IMAP internal date:
* dd-mon-yyyy hh:mm:ss with mon characters (i.e. 'Apr' for april)
* return value is valid until next function call.
* NOTE: if date is not valid, IMAP_STANDARD_DATE is returned
*/
char *date_sql2imap(const char *sqldate)
{
struct tm tm_sql_date;
time_t ltime;
char *last;
char t[IMAP_INTERNALDATE_LEN];
char q[IMAP_INTERNALDATE_LEN];
// bsd needs:
memset(&tm_sql_date, 0, sizeof(struct tm));
last = strptime(sqldate,"%Y-%m-%d %H:%M:%S", &tm_sql_date);
if ( (last == NULL) || (*last != '\0') ) {
strcpy(_imapdate, IMAP_STANDARD_DATE);
return _imapdate;
}
strftime(q, sizeof(q), "%d-%b-%Y %H:%M:%S", &tm_sql_date);
ltime = mktime (&tm_sql_date);
localtime_r(<ime, &tm_sql_date);
strftime(t, sizeof(t), "%z", &tm_sql_date);
if (t[0] != '%') {
snprintf(_imapdate,IMAP_INTERNALDATE_LEN, "%s %s", q, t);
return _imapdate;
}
// oops, no %z on solaris (FIXME)
snprintf(_imapdate,IMAP_INTERNALDATE_LEN, "%s +0000", q);
return _imapdate;
}
/*
* convert TO a mySQL date (yyyy-mm-dd) FROM a valid IMAP internal date:
* 0123456789
* dd-mon-yyyy with mon characters (i.e. 'Apr' for april)
* 01234567890
* OR
* d-mon-yyyy
* return value is valid until next function call.
*/
char *date_imap2sql(const char *imapdate)
{
struct tm tm;
char *last_char;
// bsd needs this:
memset(&tm, 0, sizeof(struct tm));
last_char = strptime(imapdate, "%d-%b-%Y", &tm);
if (last_char == NULL || *last_char != '\0') {
trace(TRACE_DEBUG, "%s,%s: error parsing IMAP date %s",
__FILE__, __func__, imapdate);
return NULL;
}
(void) strftime(_sqldate, SQL_INTERNALDATE_LEN,
"%Y-%m-%d 00:00:00", &tm);
return _sqldate;
}
int num_from_imapdate(const char *date)
{
int j = 0, i;
char datenum[] = "YYYYMMDD";
char sub[4];
if (date[1] == ' ' || date[1] == '-')
j = 1;
strncpy(datenum, &date[7 - j], 4);
strncpy(sub, &date[3 - j], 3);
sub[3] = 0;
for (i = 0; i < 12; i++) {
if (strcasecmp(sub, month_desc[i]) == 0)
break;
}
i++;
if (i > 12)
i = 12;
sprintf(&datenum[4], "%02d", i);
if (j) {
datenum[6] = '0';
datenum[7] = date[0];
} else {
datenum[6] = date[0];
datenum[7] = date[1];
}
return atoi(datenum);
}
void g_list_destroy(GList *l)
{
g_list_foreach(l,(GFunc)g_free,NULL);
g_list_free(l);
}
static gboolean traverse_tree_keys(gpointer key, gpointer value UNUSED, GList **l)
{
*(GList **)l = g_list_prepend(*(GList **)l, key);
return FALSE;
}
static gboolean traverse_tree_values(gpointer key UNUSED, gpointer value, GList **l)
{
*(GList **)l = g_list_prepend(*(GList **)l, value);
return FALSE;
}
GList * g_tree_keys(GTree *tree)
{
GList *l = NULL;
g_tree_foreach(tree, (GTraverseFunc)traverse_tree_keys, &l);
return g_list_reverse(l);
}
GList * g_tree_values(GTree *tree)
{
GList *l = NULL;
g_tree_foreach(tree, (GTraverseFunc)traverse_tree_values, &l);
return g_list_reverse(l);
}
/*
* boolean merge of two GTrees. The result is stored in GTree *a.
* the state of GTree *b is undefined: it may or may not have been changed,
* depending on whether or not key/value pairs were moved from b to a.
* Both trees are safe to destroy afterwards, assuming g_tree_new_full was used
* for their construction.
*/
static gboolean tree_print(gpointer key, gpointer value, gpointer data UNUSED)
{
if (! (key && value))
return TRUE;
u64_t *k = (u64_t *)key;
u64_t *v = (u64_t *)value;
trace(TRACE_DEBUG,"%s,%s: %llu: %llu\n", __FILE__, __func__, *k, *v);
return FALSE;
}
void tree_dump(GTree *t)
{
trace(TRACE_DEBUG,"%s,%s: start",__FILE__,__func__);
g_tree_foreach(t,(GTraverseFunc)tree_print,NULL);
trace(TRACE_DEBUG,"%s,%s: done",__FILE__,__func__);
}
static gboolean traverse_tree_merger(gpointer key, gpointer value UNUSED, tree_merger_t **merger)
{
tree_merger_t *t = *(tree_merger_t **)merger;
GTree *tree = t->tree;
int condition = t->condition;
switch(condition) {
case IST_SUBSEARCH_NOT:
break;
default:
case IST_SUBSEARCH_OR:
case IST_SUBSEARCH_AND:
if (! g_tree_lookup(tree,key))
(*(tree_merger_t **)merger)->list = g_list_prepend((*(tree_merger_t **)merger)->list,key);
break;
}
return FALSE;
}
int g_tree_merge(GTree *a, GTree *b, int condition)
{
char *type = NULL;
GList *keys = NULL;
int alen = 0, blen=0, klen=0;
gpointer key;
gpointer value;
g_return_val_if_fail(a && b,1);
tree_merger_t *merger = g_new0(tree_merger_t,1);
alen = g_tree_nnodes(a);
blen = g_tree_nnodes(b);
switch(condition) {
case IST_SUBSEARCH_AND:
type=g_strdup("AND");
/* delete from A all keys not in B */
merger->tree = b;
merger->condition = IST_SUBSEARCH_AND;
g_tree_foreach(a,(GTraverseFunc)traverse_tree_merger, &merger);
keys = g_list_first(merger->list);
if (! (klen = g_list_length(keys)))
break;
if (klen > 1)
keys = g_list_reverse(merger->list);
while (keys->data) {
g_tree_remove(a,keys->data);
if (! g_list_next(keys))
break;
keys = g_list_next(keys);
}
break;
case IST_SUBSEARCH_OR:
type=g_strdup("OR");
if (! g_tree_nnodes(b) > 0)
break;
merger->tree = a;
merger->condition = IST_SUBSEARCH_OR;
g_tree_foreach(b,(GTraverseFunc)traverse_tree_merger, &merger);
keys = g_list_first(merger->list);
if (! (klen = g_list_length(keys)))
break;
if (klen > 1)
keys = g_list_reverse(keys);
/* add to A all keys in B */
while (keys->data) {
g_tree_lookup_extended(b,keys->data,&key,&value);
g_tree_steal(b,keys->data);
g_tree_insert(a,key,value);
if (! g_list_next(keys))
break;
keys = g_list_next(keys);
}
break;
case IST_SUBSEARCH_NOT:
type=g_strdup("NOT");
keys = g_tree_keys(b);
if (! g_list_length(keys))
break;
while (keys->data) {
// remove from A keys also in B
if (g_tree_lookup(a,keys->data)) {
g_tree_remove(a,keys->data);
} else {
// add to A all keys in B not in A
g_tree_lookup_extended(b,keys->data,&key,&value);
g_tree_steal(b,keys->data);
g_tree_insert(a,key,value);
}
if (! g_list_next(keys))
break;
keys = g_list_next(keys);
}
break;
}
trace(TRACE_DEBUG,"%s,%s: a[%d] [%s] b[%d] -> a[%d]",
__FILE__, __func__,
alen, type, blen,
g_tree_nnodes(a));
g_free(merger);
g_free(type);
return 0;
}
gint ucmp(const u64_t *a, const u64_t *b)
{
u64_t x,y;
x = (u64_t)*a;
y = (u64_t)*b;
if (x>y)
return 1;
if (x==y)
return 0;
return -1;
}
/* Read from instream until ".\r\n", discarding what is read. */
int discard_client_input(FILE * instream)
{
int ch, ns, l;
clearerr(instream);
for (ns = 0; (ch = fgetc(instream)) != EOF;) {
if (ch == '\r') {
if (ns == 4) {
/* \r\n.\r */
ns = 5;
} else {
/* \r */
ns = 1;
}
} else if (ch == '\n') {
if (ns == 1) {
/* \r\n */
ns = 2;
} else if (ns == 5) {
/* complete: \r\n.\r\n */
return 0;
} else {
/* .\n ? */
trace(TRACE_ERROR, "%s,%s: bare LF.",
__FILE__, __func__);
}
} else if (ch == '.' && ns == 3) {
/* \r\n. */
ns = 4;
}
if ((ch = fileno(instream)) != -1) {
/* okay, look for error slippage */
l = 0;
if (getpeername(ns,(struct sockaddr *)"",&l) == -1 && errno != ENOTSOCK) {
trace(TRACE_ERROR, "%s,%s: unexpected failure from socket layer (client hangup?)",
__FILE__, __func__);
}
}
}
trace(TRACE_ERROR, "%s,%s: unexpected EOF from stdio (client hangup?)",
__FILE__, __func__);
return 0;
}
/* Following the advice of:
* "Secure Programming for Linux and Unix HOWTO"
* Chapter 8: Carefully Call Out to Other Resources */
char * dm_shellesc(const char * command)
{
char *safe_command;
int pos, end, len;
// These are the potentially unsafe characters:
// & ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r
// # ! \t \ (space)
len = strlen(command);
if (! (safe_command = g_new0(char,(len + 1) * 2 + 1)))
return NULL;
for (pos = end = 0; pos < len; pos++) {
switch (command[pos]) {
case '&':
case ';':
case '`':
case '\'':
case '\\':
case '"':
case '|':
case '*':
case '?':
case '~':
case '<':
case '>':
case '^':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case '$':
case '\n':
case '\r':
case '\t':
case ' ':
case '#':
case '!':
// Add an escape before the offending char.
safe_command[end++] = '\\';
default:
// And then put in the character itself.
safe_command[end++] = command[pos];
break;
}
}
/* The string is already initialized,
* but let's be extra double sure. */
safe_command[end] = '\0';
return safe_command;
}
syntax highlighted by Code2HTML, v. 0.9.1