+static void ircclient_userlist_clear(struct IRCChannel *channel) {
+ struct IRCChannelMember *member, *next_member;
+ for(member = channel->userlist; member; member = next_member) {
+ next_member = member->next;
+ free(member->nick);
+ free(member);
+ }
+ channel->userlist = NULL;
+}
+
+static struct IRCChannelMember *ircclient_userlist_add(struct IRCChannel *channel, char *nick) {
+ struct IRCChannelMember *member;
+ for(member = channel->userlist; member; member = member->next) {
+ if(!stricmp(member->nick, nick)) return member; //prevent duplicates
+ }
+ member = calloc(1, sizeof(*member));
+ member->nick = strdup(nick);
+ member->next = channel->userlist;
+ if(channel->userlist)
+ channel->userlist->prev = member;
+ channel->userlist = member;
+ return member;
+}
+
+static void ircclient_userlist_del(struct IRCChannel *channel, char *nick) {
+ struct IRCChannelMember *member;
+ for(member = channel->userlist; member; member = member->next) {
+ if(!stricmp(member->nick, nick)) break;
+ }
+ if(!member) return;
+ if(member->prev)
+ member->prev->next = member->next;
+ else
+ channel->userlist = member->next;
+ if(member->next)
+ member->next->prev = member->prev;
+ free(member->nick);
+ free(member);
+}
+
+static void ircclient_raw005_parse(struct IRCClient *client, char **argv, int argc) {
+ int i;
+ char *name;
+ char *value;
+ for(i = 0; i < argc; i++) {
+ name = argv[i];
+ value = strchr(argv[i], '=');
+ if(value) {
+ *value = '\0';
+ value++;
+ }
+ if(!stricmp(name, "PREFIX")) {
+ //parse prefixes
+ if(*value != '(') continue;
+ value++;
+ char *prefixes_char = value;
+ value = strchr(value, ')');
+ if(!value) continue;
+ *value = '\0';
+ value++;
+ if(strlen(prefixes_char) == strlen(value)) {
+ client->network_prefixes = strdup(value);
+ client->network_prefixes_char = strdup(prefixes_char);
+ }
+ }
+ }
+}
+
+static void ircclient_chanmode_parse(struct IRCClient *client, struct IRCChannel *channel, char *mode, char **argv, int argc) {
+ int add = 1;
+ int arg = 0;
+ int i, j;
+ char *carg;
+ struct IRCChannelMember *member;
+ while(*mode) {
+ if(*mode == '+')
+ add = 1;
+ else if(*mode == '-')
+ add = 0;
+ else {
+ char *prefix_chars = client->network_prefixes_char ? client->network_prefixes_char : "ov";
+ i = 0;
+ while(prefix_chars[i]) {
+ if(prefix_chars[i] == *mode) {
+ carg = argv[arg++];
+ member = ircclient_userlist_add(channel, carg);
+ if(add)
+ member->modes |= (1 << i);
+ else
+ member->modes &= ~(1 << i);
+ goto ircclient_chanmode_parse_next;
+ }
+ i++;
+ }
+ char *chanmodes = client->network_chanmodes ? client->network_chanmodes : "b,k,l,";
+ i = 0;
+ j = 0;
+ while(chanmodes[i]) {
+ if(chanmodes[i] == ',') {
+ j++;
+ if(j == 2 && !add) break;
+ if(j == 3) break;
+ }
+ if(chanmodes[i] == *mode) {
+ arg++;
+ goto ircclient_chanmode_parse_next;
+ }
+ }
+ //default mode without parameter...
+ }
+ ircclient_chanmode_parse_next:
+ mode++;
+ }
+}
+
+static int ircclient_is_channel_prefix(struct IRCClient *client, char prefix) {
+ if(!client->network_chantypes) {
+ return (prefix == '#'); //default
+ }
+ int i = 0;
+ while(client->network_chantypes[i]) {
+ if(prefix == client->network_chantypes[i])
+ return 1;
+ i++;
+ }
+ return 0;
+}
+
+static int ircclient_is_chanuser_prefix(struct IRCClient *client, char prefix, int *prefix_id) {
+ char *prefixes = client->network_prefixes ? client->network_prefixes : "@+";
+ int i;
+ for(i = 0; prefixes[i]; i++) {
+ if(prefixes[i] == prefix) {
+ *prefix_id = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int ircclient_build_chanuser_prefix(struct IRCClient *client, struct IRCChannelMember *member, char *buffer, int highest_only) {
+ char *prefixes = client->network_prefixes ? client->network_prefixes : "@+";
+ int i;
+ int j = 0;
+ for(i = 0; prefixes[i]; i++) {
+ if(member->modes & (1 << i)) {
+ buffer[j++] = prefixes[i];
+ if(highest_only) break;
+ }
+ }
+ buffer[j] = '\0';
+ return j;
+}
+