1 /*
2  * Copyright (C) 2007 Colin DIDIER
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 #include <string.h>
19 
20 #include "module.h"
21 #include "signals.h"
22 
23 #include "rosters.h"
24 #include "muc-nicklist.h"
25 
26 const char *xmpp_nicklist_affiliation[] = {
27 	"none",
28 	"owner",
29 	"admin",
30 	"member",
31 	"outcast",
32 	NULL
33 };
34 
35 const char *xmpp_nicklist_role[] = {
36 	"none",
37 	"moderator",
38 	"participant",
39 	"visitor",
40 	NULL
41 };
42 
43 XMPP_NICK_REC *
xmpp_nicklist_insert(MUC_REC * channel,const char * nickname,const char * full_jid)44 xmpp_nicklist_insert(MUC_REC *channel, const char *nickname,
45     const char *full_jid)
46 {
47 	XMPP_NICK_REC *rec;
48 
49 	g_return_val_if_fail(IS_MUC(channel), NULL);
50 	g_return_val_if_fail(nickname != NULL, NULL);
51 	rec = g_new0(XMPP_NICK_REC, 1);
52 	rec->nick = g_strdup(nickname);
53 	rec->host = (full_jid != NULL) ?
54 	    g_strdup(full_jid) : g_strconcat(channel->name, "/", rec->nick, (void *)NULL);
55 	rec->show = XMPP_PRESENCE_AVAILABLE;
56 	rec->status = NULL;
57 	rec->affiliation = XMPP_NICKLIST_AFFILIATION_NONE;
58 	rec->role = XMPP_NICKLIST_ROLE_NONE;
59 	nicklist_insert(CHANNEL(channel), (NICK_REC *)rec);
60 	return rec;
61 }
62 
63 static void
nick_hash_add(CHANNEL_REC * channel,NICK_REC * nick)64 nick_hash_add(CHANNEL_REC *channel, NICK_REC *nick)
65 {
66 	NICK_REC *list;
67 
68 	nick->next = NULL;
69 	list = g_hash_table_lookup(channel->nicks, nick->nick);
70         if (list == NULL)
71 		g_hash_table_insert(channel->nicks, nick->nick, nick);
72 	else {
73                 /* multiple nicks with same name */
74 		while (list->next != NULL)
75 			list = list->next;
76 		list->next = nick;
77 	}
78 	/* move our own nick to beginning of the nick list.. */
79 	if (nick == channel->ownnick)
80 		nicklist_set_own(channel, nick);
81 }
82 
83 static void
nick_hash_remove(CHANNEL_REC * channel,NICK_REC * nick)84 nick_hash_remove(CHANNEL_REC *channel, NICK_REC *nick)
85 {
86 	NICK_REC *list;
87 
88 	list = g_hash_table_lookup(channel->nicks, nick->nick);
89 	if (list == NULL)
90 		return;
91 	if (list == nick || list->next == NULL) {
92 		g_hash_table_remove(channel->nicks, nick->nick);
93 		if (list->next != NULL)
94 			g_hash_table_insert(channel->nicks, nick->next->nick,
95 			    nick->next);
96 	} else {
97 		while (list->next != nick)
98 			list = list->next;
99 		list->next = nick->next;
100 	}
101 }
102 
103 void
xmpp_nicklist_rename(MUC_REC * channel,XMPP_NICK_REC * nick,const char * oldnick,const char * newnick)104 xmpp_nicklist_rename(MUC_REC *channel, XMPP_NICK_REC *nick,
105     const char *oldnick, const char *newnick)
106 {
107 
108 	g_return_if_fail(IS_MUC(channel));
109 	g_return_if_fail(IS_XMPP_NICK(nick));
110 	g_return_if_fail(oldnick != NULL);
111 	g_return_if_fail(newnick != NULL);
112 	/* remove old nick from hash table */
113 	nick_hash_remove(CHANNEL(channel), NICK(nick));
114 	g_free(nick->nick);
115 	nick->nick = g_strdup(newnick);
116 	/* add new nick to hash table */
117 	nick_hash_add(CHANNEL(channel), NICK(nick));
118 	signal_emit("nicklist changed", 3, channel, nick, oldnick);
119 	if (strcmp(oldnick, channel->nick) == 0) {
120 		nicklist_set_own(CHANNEL(channel), NICK(nick));
121 		g_free(channel->nick);
122 		channel->nick = g_strdup(newnick);
123 	}
124 }
125 
126 int
xmpp_nicklist_get_affiliation(const char * affiliation)127 xmpp_nicklist_get_affiliation(const char *affiliation)
128 {
129 	if (affiliation != NULL) {
130 		if (g_ascii_strcasecmp(affiliation,
131 		    xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_OWNER]) == 0)
132 			return XMPP_NICKLIST_AFFILIATION_OWNER;
133 		else if (g_ascii_strcasecmp(affiliation,
134 		    xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_ADMIN]) == 0)
135 			return XMPP_NICKLIST_AFFILIATION_ADMIN;
136 		else if (g_ascii_strcasecmp(affiliation,
137 		    xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_MEMBER]) == 0)
138 			return XMPP_NICKLIST_AFFILIATION_MEMBER;
139 		else if (g_ascii_strcasecmp(affiliation,
140 		    xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_OUTCAST]) == 0)
141 			return XMPP_NICKLIST_AFFILIATION_OUTCAST;
142 	}
143 	return XMPP_NICKLIST_AFFILIATION_NONE;
144 }
145 
146 int
xmpp_nicklist_get_role(const char * role)147 xmpp_nicklist_get_role(const char *role)
148 {
149 	if (role != NULL) {
150 		if (g_ascii_strcasecmp(role,
151 		    xmpp_nicklist_role[XMPP_NICKLIST_ROLE_MODERATOR]) == 0)
152 			return XMPP_NICKLIST_ROLE_MODERATOR;
153 		else if (g_ascii_strcasecmp(role,
154 		    xmpp_nicklist_role[XMPP_NICKLIST_ROLE_PARTICIPANT]) == 0)
155 			return XMPP_NICKLIST_ROLE_PARTICIPANT;
156 		else if (g_ascii_strcasecmp(role,
157 		    xmpp_nicklist_role[XMPP_NICKLIST_ROLE_VISITOR]) == 0)
158 			return XMPP_NICKLIST_ROLE_VISITOR;
159 	}
160 	return XMPP_NICKLIST_ROLE_NONE;
161 }
162 
163 gboolean
xmpp_nicklist_modes_changed(XMPP_NICK_REC * nick,int affiliation,int role)164 xmpp_nicklist_modes_changed(XMPP_NICK_REC *nick, int affiliation, int role)
165 {
166 	g_return_val_if_fail(IS_XMPP_NICK(nick), FALSE);
167 	return nick->affiliation != affiliation || nick->role != role;
168 }
169 
170 void
xmpp_nicklist_set_modes(XMPP_NICK_REC * nick,int affiliation,int role)171 xmpp_nicklist_set_modes(XMPP_NICK_REC *nick, int affiliation, int role)
172 {
173 	g_return_if_fail(IS_XMPP_NICK(nick));
174 
175 	nick->affiliation = affiliation;
176 	nick->role = role;
177 	switch (affiliation) {
178 	case XMPP_NICKLIST_AFFILIATION_OWNER:
179 		nick->prefixes[0] = '&';
180 		nick->prefixes[1] = '\0';
181 		nick->op = TRUE;
182 		break;
183 	case XMPP_NICKLIST_AFFILIATION_ADMIN:
184 		nick->prefixes[0] = '\0';
185 		nick->op = TRUE;
186 		break;
187 	default:
188 		nick->prefixes[0] = '\0';
189 		nick->op = FALSE;
190 	}
191 	switch (role) {
192 	case XMPP_NICKLIST_ROLE_MODERATOR:
193 		nick->voice = TRUE;
194 		nick->halfop = TRUE;
195 		break;
196 	case XMPP_NICKLIST_ROLE_PARTICIPANT:
197 		nick->halfop = FALSE;
198 		nick->voice = TRUE;
199 		break;
200 	default:
201 		nick->halfop = FALSE;
202 		nick->voice = FALSE;
203 	}
204 }
205 
206 void
xmpp_nicklist_set_presence(XMPP_NICK_REC * nick,int show,const char * status)207 xmpp_nicklist_set_presence(XMPP_NICK_REC *nick, int show, const char *status)
208 {
209 	g_return_if_fail(IS_XMPP_NICK(nick));
210 	nick->show = show;
211 	g_free(nick->status);
212 	nick->status = g_strdup(status);
213 }
214 
215 static void
sig_nicklist_remove(MUC_REC * channel,XMPP_NICK_REC * nick)216 sig_nicklist_remove(MUC_REC *channel, XMPP_NICK_REC *nick)
217 {
218 	if (!IS_MUC(channel) || !IS_XMPP_NICK(nick))
219 		return;
220 	g_free(nick->status);
221 }
222 
223 void
muc_nicklist_init(void)224 muc_nicklist_init(void)
225 {
226 	signal_add("nicklist remove", sig_nicklist_remove);
227 }
228 
229 void
muc_nicklist_deinit(void)230 muc_nicklist_deinit(void)
231 {
232 	signal_remove("nicklist remove", sig_nicklist_remove);
233 }
234