mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-14 09:40:20 +00:00
add xchat r1489
This commit is contained in:
431
src/common/chanopt.c
Normal file
431
src/common/chanopt.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/* per-channel/dialog settings :: /CHANOPT */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xchat.h"
|
||||
|
||||
#include "cfgfiles.h"
|
||||
#include "server.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "xchatc.h"
|
||||
|
||||
|
||||
static GSList *chanopt_list = NULL;
|
||||
static gboolean chanopt_open = FALSE;
|
||||
static gboolean chanopt_changed = FALSE;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char *alias; /* old names from 2.8.4 */
|
||||
int offset;
|
||||
} channel_options;
|
||||
|
||||
#define S_F(xx) STRUCT_OFFSET_STR(struct session,xx)
|
||||
|
||||
static const channel_options chanopt[] =
|
||||
{
|
||||
{"alert_beep", "BEEP", S_F(alert_beep)},
|
||||
{"alert_taskbar", NULL, S_F(alert_taskbar)},
|
||||
{"alert_tray", "TRAY", S_F(alert_tray)},
|
||||
|
||||
{"text_hidejoinpart", "CONFMODE", S_F(text_hidejoinpart)},
|
||||
{"text_logging", NULL, S_F(text_logging)},
|
||||
{"text_scrollback", NULL, S_F(text_scrollback)},
|
||||
};
|
||||
|
||||
#undef S_F
|
||||
|
||||
static char *
|
||||
chanopt_value (guint8 val)
|
||||
{
|
||||
switch (val)
|
||||
{
|
||||
case SET_OFF:
|
||||
return "OFF";
|
||||
case SET_ON:
|
||||
return "ON";
|
||||
default:
|
||||
return "{unset}";
|
||||
}
|
||||
}
|
||||
|
||||
/* handle the /CHANOPT command */
|
||||
|
||||
int
|
||||
chanopt_command (session *sess, char *tbuf, char *word[], char *word_eol[])
|
||||
{
|
||||
int dots, i = 0, j, p = 0;
|
||||
guint8 val;
|
||||
int offset = 2;
|
||||
char *find;
|
||||
gboolean quiet = FALSE;
|
||||
int newval = -1;
|
||||
|
||||
if (!strcmp (word[2], "-quiet"))
|
||||
{
|
||||
quiet = TRUE;
|
||||
offset++;
|
||||
}
|
||||
|
||||
find = word[offset++];
|
||||
|
||||
if (word[offset][0])
|
||||
{
|
||||
if (!strcasecmp (word[offset], "ON"))
|
||||
newval = 1;
|
||||
else if (!strcasecmp (word[offset], "OFF"))
|
||||
newval = 0;
|
||||
else if (word[offset][0] == 'u')
|
||||
newval = SET_DEFAULT;
|
||||
else
|
||||
newval = atoi (word[offset]);
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
PrintTextf (sess, "\002Network\002: %s \002Channel\002: %s\n",
|
||||
sess->server->network ? server_get_network (sess->server, TRUE) : _("<none>"),
|
||||
sess->channel[0] ? sess->channel : _("<none>"));
|
||||
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
if (find[0] == 0 || match (find, chanopt[i].name) || (chanopt[i].alias && match (find, chanopt[i].alias)))
|
||||
{
|
||||
if (newval != -1) /* set new value */
|
||||
{
|
||||
*(guint8 *)G_STRUCT_MEMBER_P(sess, chanopt[i].offset) = newval;
|
||||
}
|
||||
|
||||
if (!quiet) /* print value */
|
||||
{
|
||||
strcpy (tbuf, chanopt[i].name);
|
||||
p = strlen (tbuf);
|
||||
|
||||
tbuf[p++] = 3;
|
||||
tbuf[p++] = '2';
|
||||
|
||||
dots = 20 - strlen (chanopt[i].name);
|
||||
|
||||
for (j = 0; j < dots; j++)
|
||||
tbuf[p++] = '.';
|
||||
tbuf[p++] = 0;
|
||||
|
||||
val = G_STRUCT_MEMBER (guint8, sess, chanopt[i].offset);
|
||||
PrintTextf (sess, "%s\0033:\017 %s", tbuf, chanopt_value (val));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* is a per-channel setting set? Or is it UNSET and
|
||||
* the global version is set? */
|
||||
|
||||
gboolean
|
||||
chanopt_is_set (unsigned int global, guint8 per_chan_setting)
|
||||
{
|
||||
if (per_chan_setting == SET_DEFAULT)
|
||||
return global;
|
||||
|
||||
return per_chan_setting;
|
||||
}
|
||||
|
||||
/* additive version */
|
||||
|
||||
gboolean
|
||||
chanopt_is_set_a (unsigned int global, guint8 per_chan_setting)
|
||||
{
|
||||
if (per_chan_setting == SET_DEFAULT)
|
||||
return global;
|
||||
|
||||
return per_chan_setting || global;
|
||||
}
|
||||
|
||||
/* === below is LOADING/SAVING stuff only === */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Per-Channel Alerts */
|
||||
/* use a byte, because we need a pointer to each element */
|
||||
guint8 alert_beep;
|
||||
guint8 alert_taskbar;
|
||||
guint8 alert_tray;
|
||||
|
||||
/* Per-Channel Settings */
|
||||
guint8 text_hidejoinpart;
|
||||
guint8 text_logging;
|
||||
guint8 text_scrollback;
|
||||
|
||||
char *network;
|
||||
char *channel;
|
||||
|
||||
} chanopt_in_memory;
|
||||
|
||||
|
||||
static chanopt_in_memory *
|
||||
chanopt_find (char *network, char *channel, gboolean add_new)
|
||||
{
|
||||
GSList *list;
|
||||
chanopt_in_memory *co;
|
||||
int i;
|
||||
|
||||
for (list = chanopt_list; list; list = list->next)
|
||||
{
|
||||
co = list->data;
|
||||
if (!strcasecmp (co->channel, channel) &&
|
||||
!strcasecmp (co->network, network))
|
||||
return co;
|
||||
}
|
||||
|
||||
if (!add_new)
|
||||
return NULL;
|
||||
|
||||
/* allocate a new one */
|
||||
co = g_malloc0 (sizeof (chanopt_in_memory));
|
||||
co->channel = g_strdup (channel);
|
||||
co->network = g_strdup (network);
|
||||
|
||||
/* set all values to SET_DEFAULT */
|
||||
i = 0;
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
*(guint8 *)G_STRUCT_MEMBER_P(co, chanopt[i].offset) = SET_DEFAULT;
|
||||
i++;
|
||||
}
|
||||
|
||||
chanopt_list = g_slist_prepend (chanopt_list, co);
|
||||
chanopt_changed = TRUE;
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
static void
|
||||
chanopt_add_opt (chanopt_in_memory *co, char *var, int new_value)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
if (!strcmp (var, chanopt[i].name))
|
||||
{
|
||||
*(guint8 *)G_STRUCT_MEMBER_P(co, chanopt[i].offset) = new_value;
|
||||
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* load chanopt.conf from disk into our chanopt_list GSList */
|
||||
|
||||
static void
|
||||
chanopt_load_all (void)
|
||||
{
|
||||
int fh;
|
||||
char buf[256];
|
||||
char *eq;
|
||||
char *network = NULL;
|
||||
chanopt_in_memory *current = NULL;
|
||||
|
||||
/* 1. load the old file into our GSList */
|
||||
fh = xchat_open_file ("chanopt.conf", O_RDONLY, 0, 0);
|
||||
if (fh != -1)
|
||||
{
|
||||
while (waitline (fh, buf, sizeof buf, FALSE) != -1)
|
||||
{
|
||||
eq = strchr (buf, '=');
|
||||
if (!eq)
|
||||
continue;
|
||||
eq[0] = 0;
|
||||
|
||||
if (eq != buf && eq[-1] == ' ')
|
||||
eq[-1] = 0;
|
||||
|
||||
if (!strcmp (buf, "network"))
|
||||
{
|
||||
g_free (network);
|
||||
network = g_strdup (eq + 2);
|
||||
}
|
||||
else if (!strcmp (buf, "channel"))
|
||||
{
|
||||
current = chanopt_find (network, eq + 2, TRUE);
|
||||
chanopt_changed = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current)
|
||||
chanopt_add_opt (current, buf, atoi (eq + 2));
|
||||
}
|
||||
|
||||
}
|
||||
close (fh);
|
||||
g_free (network);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chanopt_load (session *sess)
|
||||
{
|
||||
int i;
|
||||
guint8 val;
|
||||
chanopt_in_memory *co;
|
||||
char *network;
|
||||
|
||||
if (sess->channel[0] == 0)
|
||||
return;
|
||||
|
||||
network = server_get_network (sess->server, FALSE);
|
||||
if (!network)
|
||||
return;
|
||||
|
||||
if (!chanopt_open)
|
||||
{
|
||||
chanopt_open = TRUE;
|
||||
chanopt_load_all ();
|
||||
}
|
||||
|
||||
co = chanopt_find (network, sess->channel, FALSE);
|
||||
if (!co)
|
||||
return;
|
||||
|
||||
/* fill in all the sess->xxxxx fields */
|
||||
i = 0;
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
val = G_STRUCT_MEMBER(guint8, co, chanopt[i].offset);
|
||||
*(guint8 *)G_STRUCT_MEMBER_P(sess, chanopt[i].offset) = val;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chanopt_save (session *sess)
|
||||
{
|
||||
int i;
|
||||
guint8 vals;
|
||||
guint8 valm;
|
||||
chanopt_in_memory *co;
|
||||
char *network;
|
||||
|
||||
if (sess->channel[0] == 0)
|
||||
return;
|
||||
|
||||
network = server_get_network (sess->server, FALSE);
|
||||
if (!network)
|
||||
return;
|
||||
|
||||
/* 2. reconcile sess with what we loaded from disk */
|
||||
|
||||
co = chanopt_find (network, sess->channel, TRUE);
|
||||
|
||||
i = 0;
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
vals = G_STRUCT_MEMBER(guint8, sess, chanopt[i].offset);
|
||||
valm = G_STRUCT_MEMBER(guint8, co, chanopt[i].offset);
|
||||
|
||||
if (vals != valm)
|
||||
{
|
||||
*(guint8 *)G_STRUCT_MEMBER_P(co, chanopt[i].offset) = vals;
|
||||
chanopt_changed = TRUE;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chanopt_save_one_channel (chanopt_in_memory *co, int fh)
|
||||
{
|
||||
int i;
|
||||
char buf[256];
|
||||
guint8 val;
|
||||
|
||||
snprintf (buf, sizeof (buf), "%s = %s\n", "network", co->network);
|
||||
write (fh, buf, strlen (buf));
|
||||
|
||||
snprintf (buf, sizeof (buf), "%s = %s\n", "channel", co->channel);
|
||||
write (fh, buf, strlen (buf));
|
||||
|
||||
i = 0;
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
val = G_STRUCT_MEMBER (guint8, co, chanopt[i].offset);
|
||||
if (val != SET_DEFAULT)
|
||||
{
|
||||
snprintf (buf, sizeof (buf), "%s = %d\n", chanopt[i].name, val);
|
||||
write (fh, buf, strlen (buf));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chanopt_save_all (void)
|
||||
{
|
||||
int i;
|
||||
int num_saved;
|
||||
int fh;
|
||||
GSList *list;
|
||||
chanopt_in_memory *co;
|
||||
guint8 val;
|
||||
|
||||
if (!chanopt_list || !chanopt_changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fh = xchat_open_file ("chanopt.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
|
||||
if (fh == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (num_saved = 0, list = chanopt_list; list; list = list->next)
|
||||
{
|
||||
co = list->data;
|
||||
|
||||
i = 0;
|
||||
while (i < sizeof (chanopt) / sizeof (channel_options))
|
||||
{
|
||||
val = G_STRUCT_MEMBER (guint8, co, chanopt[i].offset);
|
||||
/* not using global/default setting, must save */
|
||||
if (val != SET_DEFAULT)
|
||||
{
|
||||
if (num_saved != 0)
|
||||
write (fh, "\n", 1);
|
||||
|
||||
chanopt_save_one_channel (co, fh);
|
||||
num_saved++;
|
||||
goto cont;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
cont:
|
||||
g_free (co->network);
|
||||
g_free (co->channel);
|
||||
g_free (co);
|
||||
}
|
||||
|
||||
close (fh);
|
||||
|
||||
/* we're quiting, no need to free */
|
||||
|
||||
/*g_slist_free (chanopt_list);
|
||||
chanopt_list = NULL;
|
||||
|
||||
chanopt_open = FALSE;
|
||||
chanopt_changed = FALSE;*/
|
||||
}
|
||||
Reference in New Issue
Block a user