Now inbound_cap_ls() can enable extensions when a bouncer uses a namespace for the...
[rofl0r-ixchat.git] / src / common / chanopt.c
bloba4fd8faaa8f90a86aa7c742481208d9881f4debc
1 /* per-channel/dialog settings :: /CHANOPT */
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <errno.h>
12 #include "xchat.h"
14 #include "cfgfiles.h"
15 #include "server.h"
16 #include "text.h"
17 #include "util.h"
18 #include "xchatc.h"
21 static GSList *chanopt_list = NULL;
22 static gboolean chanopt_open = FALSE;
23 static gboolean chanopt_changed = FALSE;
26 typedef struct
28 char *name;
29 char *alias; /* old names from 2.8.4 */
30 int offset;
31 } channel_options;
33 #define S_F(xx) STRUCT_OFFSET_STR(struct session,xx)
35 static const channel_options chanopt[] =
37 {"alert_beep", "BEEP", S_F(alert_beep)},
38 {"alert_taskbar", NULL, S_F(alert_taskbar)},
39 {"alert_tray", "TRAY", S_F(alert_tray)},
41 {"text_hidejoinpart", "CONFMODE", S_F(text_hidejoinpart)},
42 {"text_logging", NULL, S_F(text_logging)},
43 {"text_scrollback", NULL, S_F(text_scrollback)},
46 #undef S_F
48 static char *
49 chanopt_value (guint8 val)
51 switch (val)
53 case SET_OFF:
54 return "OFF";
55 case SET_ON:
56 return "ON";
57 default:
58 return "{unset}";
62 /* handle the /CHANOPT command */
64 int
65 chanopt_command (session *sess, char *tbuf, char *word[], char *word_eol[])
67 int dots, i = 0, j, p = 0;
68 guint8 val;
69 int offset = 2;
70 char *find;
71 gboolean quiet = FALSE;
72 int newval = -1;
74 if (!strcmp (word[2], "-quiet"))
76 quiet = TRUE;
77 offset++;
80 find = word[offset++];
82 if (word[offset][0])
84 if (!strcasecmp (word[offset], "ON"))
85 newval = 1;
86 else if (!strcasecmp (word[offset], "OFF"))
87 newval = 0;
88 else if (word[offset][0] == 'u')
89 newval = SET_DEFAULT;
90 else
91 newval = atoi (word[offset]);
94 if (!quiet)
95 PrintTextf (sess, "\002Network\002: %s \002Channel\002: %s\n",
96 sess->server->network ? server_get_network (sess->server, TRUE) : _("<none>"),
97 sess->channel[0] ? sess->channel : _("<none>"));
99 while (i < sizeof (chanopt) / sizeof (channel_options))
101 if (find[0] == 0 || match (find, chanopt[i].name) || (chanopt[i].alias && match (find, chanopt[i].alias)))
103 if (newval != -1) /* set new value */
105 *(guint8 *)G_STRUCT_MEMBER_P(sess, chanopt[i].offset) = newval;
108 if (!quiet) /* print value */
110 strcpy (tbuf, chanopt[i].name);
111 p = strlen (tbuf);
113 tbuf[p++] = 3;
114 tbuf[p++] = '2';
116 dots = 20 - strlen (chanopt[i].name);
118 for (j = 0; j < dots; j++)
119 tbuf[p++] = '.';
120 tbuf[p++] = 0;
122 val = G_STRUCT_MEMBER (guint8, sess, chanopt[i].offset);
123 PrintTextf (sess, "%s\0033:\017 %s", tbuf, chanopt_value (val));
126 i++;
129 return TRUE;
132 /* is a per-channel setting set? Or is it UNSET and
133 * the global version is set? */
135 gboolean
136 chanopt_is_set (unsigned int global, guint8 per_chan_setting)
138 if (per_chan_setting == SET_DEFAULT)
139 return global;
141 return per_chan_setting;
144 /* additive version */
146 gboolean
147 chanopt_is_set_a (unsigned int global, guint8 per_chan_setting)
149 if (per_chan_setting == SET_DEFAULT)
150 return global;
152 return per_chan_setting || global;
155 /* === below is LOADING/SAVING stuff only === */
157 typedef struct
159 /* Per-Channel Alerts */
160 /* use a byte, because we need a pointer to each element */
161 guint8 alert_beep;
162 guint8 alert_taskbar;
163 guint8 alert_tray;
165 /* Per-Channel Settings */
166 guint8 text_hidejoinpart;
167 guint8 text_logging;
168 guint8 text_scrollback;
170 char *network;
171 char *channel;
173 } chanopt_in_memory;
176 static chanopt_in_memory *
177 chanopt_find (char *network, char *channel, gboolean add_new)
179 GSList *list;
180 chanopt_in_memory *co;
181 int i;
183 for (list = chanopt_list; list; list = list->next)
185 co = list->data;
186 if (!strcasecmp (co->channel, channel) &&
187 !strcasecmp (co->network, network))
188 return co;
191 if (!add_new)
192 return NULL;
194 /* allocate a new one */
195 co = g_malloc0 (sizeof (chanopt_in_memory));
196 co->channel = g_strdup (channel);
197 co->network = g_strdup (network);
199 /* set all values to SET_DEFAULT */
200 i = 0;
201 while (i < sizeof (chanopt) / sizeof (channel_options))
203 *(guint8 *)G_STRUCT_MEMBER_P(co, chanopt[i].offset) = SET_DEFAULT;
204 i++;
207 chanopt_list = g_slist_prepend (chanopt_list, co);
208 chanopt_changed = TRUE;
210 return co;
213 static void
214 chanopt_add_opt (chanopt_in_memory *co, char *var, int new_value)
216 int i;
218 i = 0;
219 while (i < sizeof (chanopt) / sizeof (channel_options))
221 if (!strcmp (var, chanopt[i].name))
223 *(guint8 *)G_STRUCT_MEMBER_P(co, chanopt[i].offset) = new_value;
226 i++;
230 /* load chanopt.conf from disk into our chanopt_list GSList */
232 static void
233 chanopt_load_all (void)
235 int fh;
236 char buf[256];
237 char *eq;
238 char *network = NULL;
239 chanopt_in_memory *current = NULL;
241 /* 1. load the old file into our GSList */
242 fh = xchat_open_file ("chanopt.conf", O_RDONLY, 0, 0);
243 if (fh != -1)
245 while (waitline (fh, buf, sizeof buf, FALSE) != -1)
247 eq = strchr (buf, '=');
248 if (!eq)
249 continue;
250 eq[0] = 0;
252 if (eq != buf && eq[-1] == ' ')
253 eq[-1] = 0;
255 if (!strcmp (buf, "network"))
257 g_free (network);
258 network = g_strdup (eq + 2);
260 else if (!strcmp (buf, "channel"))
262 current = chanopt_find (network, eq + 2, TRUE);
263 chanopt_changed = FALSE;
265 else
267 if (current)
268 chanopt_add_opt (current, buf, atoi (eq + 2));
272 close (fh);
273 g_free (network);
277 void
278 chanopt_load (session *sess)
280 int i;
281 guint8 val;
282 chanopt_in_memory *co;
283 char *network;
285 if (sess->channel[0] == 0)
286 return;
288 network = server_get_network (sess->server, FALSE);
289 if (!network)
290 return;
292 if (!chanopt_open)
294 chanopt_open = TRUE;
295 chanopt_load_all ();
298 co = chanopt_find (network, sess->channel, FALSE);
299 if (!co)
300 return;
302 /* fill in all the sess->xxxxx fields */
303 i = 0;
304 while (i < sizeof (chanopt) / sizeof (channel_options))
306 val = G_STRUCT_MEMBER(guint8, co, chanopt[i].offset);
307 *(guint8 *)G_STRUCT_MEMBER_P(sess, chanopt[i].offset) = val;
308 i++;
312 void
313 chanopt_save (session *sess)
315 int i;
316 guint8 vals;
317 guint8 valm;
318 chanopt_in_memory *co;
319 char *network;
321 if (sess->channel[0] == 0)
322 return;
324 network = server_get_network (sess->server, FALSE);
325 if (!network)
326 return;
328 /* 2. reconcile sess with what we loaded from disk */
330 co = chanopt_find (network, sess->channel, TRUE);
332 i = 0;
333 while (i < sizeof (chanopt) / sizeof (channel_options))
335 vals = G_STRUCT_MEMBER(guint8, sess, chanopt[i].offset);
336 valm = G_STRUCT_MEMBER(guint8, co, chanopt[i].offset);
338 if (vals != valm)
340 *(guint8 *)G_STRUCT_MEMBER_P(co, chanopt[i].offset) = vals;
341 chanopt_changed = TRUE;
344 i++;
348 static void
349 chanopt_save_one_channel (chanopt_in_memory *co, int fh)
351 int i;
352 char buf[256];
353 guint8 val;
355 snprintf (buf, sizeof (buf), "%s = %s\n", "network", co->network);
356 write (fh, buf, strlen (buf));
358 snprintf (buf, sizeof (buf), "%s = %s\n", "channel", co->channel);
359 write (fh, buf, strlen (buf));
361 i = 0;
362 while (i < sizeof (chanopt) / sizeof (channel_options))
364 val = G_STRUCT_MEMBER (guint8, co, chanopt[i].offset);
365 if (val != SET_DEFAULT)
367 snprintf (buf, sizeof (buf), "%s = %d\n", chanopt[i].name, val);
368 write (fh, buf, strlen (buf));
370 i++;
374 void
375 chanopt_save_all (void)
377 int i;
378 int num_saved;
379 int fh;
380 GSList *list;
381 chanopt_in_memory *co;
382 guint8 val;
384 if (!chanopt_list || !chanopt_changed)
386 return;
389 fh = xchat_open_file ("chanopt.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
390 if (fh == -1)
392 return;
395 for (num_saved = 0, list = chanopt_list; list; list = list->next)
397 co = list->data;
399 i = 0;
400 while (i < sizeof (chanopt) / sizeof (channel_options))
402 val = G_STRUCT_MEMBER (guint8, co, chanopt[i].offset);
403 /* not using global/default setting, must save */
404 if (val != SET_DEFAULT)
406 if (num_saved != 0)
407 write (fh, "\n", 1);
409 chanopt_save_one_channel (co, fh);
410 num_saved++;
411 goto cont;
413 i++;
416 cont:
417 g_free (co->network);
418 g_free (co->channel);
419 g_free (co);
422 close (fh);
424 /* we're quiting, no need to free */
426 /*g_slist_free (chanopt_list);
427 chanopt_list = NULL;
429 chanopt_open = FALSE;
430 chanopt_changed = FALSE;*/