diff --git a/src/st_list.c b/src/st_list.c index 949696a..c2809be 100644 --- a/src/st_list.c +++ b/src/st_list.c @@ -662,7 +662,9 @@ void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) { g_return_if_fail(b != NULL); mwString_get(b, &str); - list_get(str, l); - g_free(str); + if (str) { + list_get(str, l); + g_free(str); + } } diff --git a/src/st_list.c.crash b/src/st_list.c.crash new file mode 100644 index 0000000..949696a --- /dev/null +++ b/src/st_list.c.crash @@ -0,0 +1,668 @@ + +/* + Meanwhile - Unofficial Lotus Sametime Community Client Library + Copyright (C) 2004 Christopher (siege) O'Brien + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#include "mw_debug.h" +#include "mw_util.h" +#include "mw_st_list.h" + + +struct mwSametimeList { + guint ver_major; + guint ver_minor; + guint ver_micro; + + GList *groups; +}; + + +struct mwSametimeGroup { + struct mwSametimeList *list; + + enum mwSametimeGroupType type; + char *name; + char *alias; + gboolean open; + + GList *users; +}; + + +struct mwSametimeUser { + struct mwSametimeGroup *group; + + enum mwSametimeUserType type; + struct mwIdBlock id; + char *name; + char *alias; +}; + + +static void user_free(struct mwSametimeUser *u) { + struct mwSametimeGroup *g; + + g = u->group; + g->users = g_list_remove(g->users, u); + + mwIdBlock_clear(&u->id); + g_free(u->name); + g_free(u->alias); + g_free(u); +} + + +static void group_free(struct mwSametimeGroup *g) { + struct mwSametimeList *l; + + l = g->list; + l->groups = g_list_remove(l->groups, g); + + while(g->users) + mwSametimeUser_free(g->users->data); + + g_free(g->name); + g_free(g->alias); + g_free(g); +} + + +static void list_free(struct mwSametimeList *l) { + while(l->groups) + mwSametimeGroup_free(l->groups->data); + + g_free(l); +} + + +struct mwSametimeList * +mwSametimeList_new() { + + struct mwSametimeList *stl; + + stl = g_new0(struct mwSametimeList, 1); + stl->ver_major = ST_LIST_MAJOR; + stl->ver_minor = ST_LIST_MINOR; + stl->ver_micro = ST_LIST_MICRO; + + return stl; +} + + +void mwSametimeList_setMajor(struct mwSametimeList *l, guint v) { + g_return_if_fail(l != NULL); + l->ver_major = v; +} + + +guint mwSametimeList_getMajor(struct mwSametimeList *l) { + g_return_val_if_fail(l != NULL, 0); + return l->ver_major; +} + + +void mwSametimeList_setMinor(struct mwSametimeList *l, guint v) { + g_return_if_fail(l != NULL); + l->ver_minor = v; +} + + +guint mwSametimeList_getMinor(struct mwSametimeList *l) { + g_return_val_if_fail(l != NULL, 0); + return l->ver_minor; +} + + +void mwSametimeList_setMicro(struct mwSametimeList *l, guint v) { + g_return_if_fail(l != NULL); + l->ver_micro = v; +} + + +guint mwSametimeList_getMicro(struct mwSametimeList *l) { + g_return_val_if_fail(l != NULL, 0); + return l->ver_micro; +} + + +GList *mwSametimeList_getGroups(struct mwSametimeList *l) { + g_return_val_if_fail(l != NULL, NULL); + return g_list_copy(l->groups); +} + + +struct mwSametimeGroup * +mwSametimeList_findGroup(struct mwSametimeList *l, + const char *name) { + GList *s; + + g_return_val_if_fail(l != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(*name != '\0', NULL); + + for(s = l->groups; s; s = s->next) { + struct mwSametimeGroup *g = s->data; + if(! strcmp(g->name, name)) return g; + } + + return NULL; +} + + +void mwSametimeList_free(struct mwSametimeList *l) { + g_return_if_fail(l != NULL); + list_free(l); +} + + +struct mwSametimeGroup * +mwSametimeGroup_new(struct mwSametimeList *list, + enum mwSametimeGroupType type, + const char *name) { + + struct mwSametimeGroup *stg; + + g_return_val_if_fail(list != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(*name != '\0', NULL); + + stg = g_new0(struct mwSametimeGroup, 1); + stg->list = list; + stg->type = type; + stg->name = g_strdup(name); + + list->groups = g_list_append(list->groups, stg); + + return stg; +} + + +enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g) { + g_return_val_if_fail(g != NULL, mwSametimeGroup_UNKNOWN); + return g->type; +} + + +const char *mwSametimeGroup_getName(struct mwSametimeGroup *g) { + g_return_val_if_fail(g != NULL, NULL); + return g->name; +} + + +void mwSametimeGroup_setAlias(struct mwSametimeGroup *g, + const char *alias) { + g_return_if_fail(g != NULL); + + g_free(g->alias); + g->alias = g_strdup(alias); +} + + +const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g) { + g_return_val_if_fail(g != NULL, NULL); + return g->alias; +} + + +void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open) { + g_return_if_fail(g != NULL); + g->open = open; +} + + +gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g) { + g_return_val_if_fail(g != NULL, FALSE); + return g->open; +} + + +struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g) { + g_return_val_if_fail(g != NULL, NULL); + return g->list; +} + + +GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g) { + g_return_val_if_fail(g != NULL, NULL); + return g_list_copy(g->users); +} + + +struct mwSametimeUser * +mwSametimeGroup_findUser(struct mwSametimeGroup *g, + struct mwIdBlock *user) { + GList *s; + + g_return_val_if_fail(g != NULL, NULL); + g_return_val_if_fail(user != NULL, NULL); + + for(s = g->users; s; s = s->next) { + struct mwSametimeUser *u = s->data; + if(mwIdBlock_equal(user, &u->id)) return u; + } + + return NULL; +} + + +void mwSametimeGroup_free(struct mwSametimeGroup *g) { + g_return_if_fail(g != NULL); + g_return_if_fail(g->list != NULL); + group_free(g); +} + + +struct mwSametimeUser * +mwSametimeUser_new(struct mwSametimeGroup *group, + enum mwSametimeUserType type, + struct mwIdBlock *id) { + + struct mwSametimeUser *stu; + + g_return_val_if_fail(group != NULL, NULL); + g_return_val_if_fail(id != NULL, NULL); + + stu = g_new0(struct mwSametimeUser, 1); + stu->group = group; + stu->type = type; + mwIdBlock_clone(&stu->id, id); + + group->users = g_list_append(group->users, stu); + + return stu; +} + + +struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u) { + g_return_val_if_fail(u != NULL, NULL); + return u->group; +} + + +enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u) { + g_return_val_if_fail(u != NULL, mwSametimeUser_UNKNOWN); + return u->type; +} + + +const char *mwSametimeUser_getUser(struct mwSametimeUser *u) { + g_return_val_if_fail(u != NULL, NULL); + return u->id.user; +} + + +const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u) { + g_return_val_if_fail(u != NULL, NULL); + return u->id.community; +} + + +void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name) { + g_return_if_fail(u != NULL); + g_free(u->name); + u->name = g_strdup(name); +} + + +const char *mwSametimeUser_getShortName(struct mwSametimeUser *u) { + g_return_val_if_fail(u != NULL, NULL); + return u->name; +} + + +void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias) { + g_return_if_fail(u != NULL); + g_free(u->alias); + u->alias = g_strdup(alias); +} + + +const char *mwSametimeUser_getAlias(struct mwSametimeUser *u) { + g_return_val_if_fail(u != NULL, NULL); + return u->alias; +} + + +void mwSametimeUser_free(struct mwSametimeUser *u) { + g_return_if_fail(u != NULL); + g_return_if_fail(u->group != NULL); + user_free(u); +} + + +static void str_replace(char *str, char from, char to) { + if(! str) return; + for(; *str; str++) if(*str == from) *str = to; +} + + +static char user_type_to_char(enum mwSametimeUserType type) { + switch(type) { + case mwSametimeUser_NORMAL: return '1'; + case mwSametimeUser_EXTERNAL: return '2'; + case mwSametimeUser_UNKNOWN: + default: return '9'; + } +} + + +static enum mwSametimeUserType user_char_to_type(char type) { + switch(type) { + case '1': return mwSametimeUser_NORMAL; + case '2': return mwSametimeUser_EXTERNAL; + default: return mwSametimeUser_UNKNOWN; + } +} + + +static void user_put(GString *str, struct mwSametimeUser *u) { + char *id, *name, *alias; + char type; + + id = g_strdup(u->id.user); + name = g_strdup(u->name); + alias = g_strdup(u->alias); + type = user_type_to_char(u->type); + + if(id) str_replace(id, ' ', ';'); + if(name) str_replace(name, ' ', ';'); + if(alias) str_replace(alias, ' ', ';'); + + if(!name && alias) { + name = alias; + alias = NULL; + } + + g_string_append_printf(str, "U %s%c:: %s,%s\r\n", + id, type, (name? name: ""), (alias? alias: "")); + + g_free(id); + g_free(name); + g_free(alias); +} + + +static char group_type_to_char(enum mwSametimeGroupType type) { + switch(type) { + case mwSametimeGroup_NORMAL: return '2'; + case mwSametimeGroup_DYNAMIC: return '3'; + case mwSametimeGroup_UNKNOWN: + default: return '9'; + } +} + + +static enum mwSametimeGroupType group_char_to_type(char type) { + switch(type) { + case '2': return mwSametimeGroup_NORMAL; + case '3': return mwSametimeGroup_DYNAMIC; + default: return mwSametimeGroup_UNKNOWN; + } +} + + +static void group_put(GString *str, struct mwSametimeGroup *g) { + char *name, *alias; + char type; + GList *gl; + + name = g_strdup(g->name); + alias = g_strdup((g->alias)? g->alias: name); + type = group_type_to_char(g->type); + + str_replace(name, ' ', ';'); + str_replace(alias, ' ', ';'); + + g_string_append_printf(str, "G %s%c %s %c\r\n", + name, type, alias, (g->open? 'O':'C')); + + for(gl = g->users; gl; gl = gl->next) { + user_put(str, gl->data); + } + + g_free(name); + g_free(alias); +} + + +/** composes a GString with the written contents of a sametime list */ +static GString *list_store(struct mwSametimeList *l) { + GString *str; + GList *gl; + + g_return_val_if_fail(l != NULL, NULL); + + str = g_string_new(NULL); + g_string_append_printf(str, "Version=%u.%u.%u\r\n", + l->ver_major, l->ver_minor, l->ver_micro); + + for(gl = l->groups; gl; gl = gl->next) { + group_put(str, gl->data); + } + + return str; +} + + +char *mwSametimeList_store(struct mwSametimeList *l) { + GString *str; + char *s; + + g_return_val_if_fail(l != NULL, NULL); + + str = list_store(l); + s = str->str; + g_string_free(str, FALSE); + return s; +} + + +void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l) { + GString *str; + guint16 len; + + g_return_if_fail(l != NULL); + g_return_if_fail(b != NULL); + + str = list_store(l); + len = (guint16) str->len; + guint16_put(b, len); + mwPutBuffer_write(b, str->str, len); + + g_string_free(str, TRUE); +} + + +static void get_version(const char *line, struct mwSametimeList *l) { + guint major = 0, minor = 0, micro = 0; + int ret; + + ret = sscanf(line, "Version=%u.%u.%u\n", &major, &minor, µ); + if(ret != 3) { + g_warning("strange sametime list version line:\n%s", line); + } + + l->ver_major = major; + l->ver_minor = minor; + l->ver_micro = micro; +} + + +static struct mwSametimeGroup *get_group(const char *line, + struct mwSametimeList *l) { + struct mwSametimeGroup *group; + char *name, *alias; + char type = '2', open = 'O'; + int ret; + + ret = strlen(line); + name = g_malloc0(ret); + alias = g_malloc0(ret); + + ret = sscanf(line, "G %s %s %c\n", + name, alias, &open); + + if(ret < 3) { + g_warning("strange sametime list group line:\n%s", line); + } + + str_replace(name, ';', ' '); + str_replace(alias, ';', ' '); + + if(name && *name) { + int l = strlen(name)-1; + type = name[l]; + name[l] = '\0'; + } + + group = g_new0(struct mwSametimeGroup, 1); + group->list = l; + group->name = name; + group->type = group_char_to_type(type); + group->alias = alias; + group->open = (open == 'O'); + + l->groups = g_list_append(l->groups, group); + + return group; +} + + +static void get_user(const char *line, struct mwSametimeGroup *g) { + struct mwSametimeUser *user; + struct mwIdBlock idb = { 0, 0 }; + char *name, *alias = NULL; + char type = '1'; + int ret; + + ret = strlen(line); + idb.user = g_malloc0(ret); + name = g_malloc0(ret); + + ret = sscanf(line, "U %s %s", + idb.user, name); + + if(ret < 2) { + g_warning("strange sametime list user line:\n%s", line); + } + + str_replace(idb.user, ';', ' '); + str_replace(name, ';', ' '); + + if(idb.user && *idb.user) { + char *tmp = strstr(idb.user, "::"); + if(tmp--) { + type = *(tmp); + *tmp = '\0'; + } + } + + if(name && *name) { + char *tmp = strrchr(name, ','); + if(tmp) { + *tmp++ = '\0'; + if(*tmp) alias = tmp; + } + } + + user = g_new0(struct mwSametimeUser, 1); + user->group = g; + user->id.user = idb.user; + user->type = user_char_to_type(type); + user->name = name; + user->alias = g_strdup(alias); + + g->users = g_list_append(g->users, user); +} + + +/** returns a line from str, and advances str */ +static char *fetch_line(char **str) { + char *start = *str; + char *end; + + /* move to first non-whitespace character */ + while(*start && g_ascii_isspace(*start)) start++; + if(! *start) return NULL; + + for(end = start + 1; *end; end++) { + if(*end == '\n' || *end == '\r') { + *(end++) = '\0'; + break; + } + } + + *str = end; + return start; +} + + +static void list_get(const char *lines, struct mwSametimeList *l) { + char *s = (char *) lines; + char *line; + + struct mwSametimeGroup *g = NULL; + + while( (line = fetch_line(&s)) ) { + switch(*line) { + case 'V': + get_version(line, l); + break; + + case 'G': + g = get_group(line, l); + break; + + case 'U': + get_user(line, g); + break; + + default: + g_warning("unknown sametime list data line:\n%s", line); + } + } +} + + +struct mwSametimeList *mwSametimeList_load(const char *data) { + struct mwSametimeList *l; + + g_return_val_if_fail(data != NULL, NULL); + + l = mwSametimeList_new(); + list_get(data, l); + + return l; +} + + +void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) { + char *str = NULL; + + g_return_if_fail(l != NULL); + g_return_if_fail(b != NULL); + + mwString_get(b, &str); + list_get(str, l); + g_free(str); +} +