source: irc.h @ 5c90890

Last change on this file since 5c90890 was 5c90890, checked in by dequis <dx@…>, at 2018-07-12T08:54:12Z

Stop using the irc->users linked list, use the hash table instead

irc_user_new() mentions that the reason this list is kept is for easy
iteration. Luckily, this is the future, and GHashTableIter exists now.

The main point of this is to get rid of the g_slist_insert_sorted() in
irc_user_set_nick() which is a particularly slow part of loading large
user lists, and scales poorly

In a test with discord, the GUILD_SYNC event is now 4 times faster, on
top of the improvements of the other bee_user hash tables patch.
Combining both patches it went from 136 to 6 seconds for 50k members.

  • Property mode set to 100644
File size: 12.9 KB
Line 
1/********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2013 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* The IRC-based UI (for now the only one)                              */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
24*/
25
26#ifndef _IRC_H
27#define _IRC_H
28
29#include <sys/socket.h>
30
31#define IRC_MAX_LINE 512
32#define IRC_MAX_ARGS 16
33#define IRC_WORD_WRAP 425
34
35#define IRC_LOGIN_TIMEOUT 60
36#define IRC_PING_STRING "PinglBee"
37
38#define UMODES "abisw"     /* Allowed umodes (although they mostly do nothing) */
39#define UMODES_PRIV "Ro"   /* Allowed, but not by user directly */
40#define UMODES_KEEP "R"    /* Don't allow unsetting using /MODE */
41#define CMODES "ntC"       /* Allowed modes */
42#define CMODE "t"          /* Default mode */
43#define UMODE "s"          /* Default mode */
44
45#define CTYPES "&#"        /* Valid channel name prefixes */
46
47typedef enum {
48        USTATUS_OFFLINE = 0,
49        USTATUS_AUTHORIZED = 1, /* Gave the correct server password (PASS). */
50        USTATUS_LOGGED_IN = 2,  /* USER+NICK(+PASS) finished. */
51        USTATUS_IDENTIFIED = 4, /* To NickServ (root). */
52        USTATUS_SHUTDOWN = 8,   /* Now used to indicate we're shutting down.
53                                   Currently just blocks irc_vawrite(). */
54        USTATUS_CAP_PENDING = 16,
55        USTATUS_SASL_PLAIN_PENDING = 32,
56
57        /* Not really status stuff, but other kinds of flags: For slightly
58           better password security, since the only way to send passwords
59           to the IRC server securely (i.e. not echoing to screen or written
60           to logfiles) is the /OPER command, try to use that command for
61           stuff that matters. */
62        OPER_HACK_IDENTIFY = 0x100,
63        OPER_HACK_IDENTIFY_NOLOAD = 0x01100,
64        OPER_HACK_IDENTIFY_FORCE  = 0x02100,
65        OPER_HACK_REGISTER = 0x200,
66        OPER_HACK_ACCOUNT_PASSWORD = 0x400,
67        OPER_HACK_ANY = 0x3700, /* To check for them all at once. */
68
69        IRC_UTF8_NICKS = 0x10000, /* Disable ASCII restrictions on buddy nicks. */
70} irc_status_t;
71
72typedef enum {
73        CAP_SASL = (1 << 0),
74        CAP_MULTI_PREFIX = (1 << 1),
75        CAP_EXTENDED_JOIN = (1 << 2),
76        CAP_AWAY_NOTIFY = (1 << 3),
77        CAP_USERHOST_IN_NAMES = (1 << 4),
78} irc_cap_flag_t;
79
80struct irc_user;
81
82typedef struct irc {
83        int fd;
84        irc_status_t status;
85        double last_pong;
86        int pinging;
87        char *sendbuffer;
88        char *readbuffer;
89        GIConv iconv, oconv;
90
91        struct irc_user *root;
92        struct irc_user *user;
93
94        char *password; /* HACK: Used to save the user's password, but before
95                           logging in, this may contain a password we should
96                           send to identify after USER/NICK are received. */
97        char *auth_backend;
98
99        char umode[8];
100
101        struct query *queries;
102        GSList *file_transfers;
103
104        GSList *users G_GNUC_DEPRECATED;
105        GSList *channels;
106        struct irc_channel *default_channel;
107        GHashTable *nick_user_hash;
108        GHashTable *watches; /* See irc_cmd_watch() */
109
110        gint r_watch_source_id;
111        gint w_watch_source_id;
112        gint ping_source_id;
113        gint login_source_id; /* To slightly delay some events at login time. */
114
115        struct otr *otr; /* OTR state and book keeping, used by the OTR plugin.
116                            TODO: Some mechanism for plugindata. */
117
118        struct bee *b;
119        guint32 caps;
120} irc_t;
121
122typedef enum {
123        /* Replaced with iu->last_channel IRC_USER_PRIVATE = 1, */
124        IRC_USER_AWAY = 2,
125
126        IRC_USER_OTR_ENCRYPTED = 0x10000,
127        IRC_USER_OTR_TRUSTED   = 0x20000,
128} irc_user_flags_t;
129
130typedef struct irc_user {
131        irc_t *irc;
132
133        char *nick;
134        char *user;
135        char *host;
136        char *fullname;
137
138        /* Nickname in lowercase for case insensitive searches */
139        char *key;
140
141        irc_user_flags_t flags;
142        struct irc_channel *last_channel;
143
144        GString *pastebuf; /* Paste buffer (combine lines into a multiline msg). */
145        guint pastebuf_timer;
146        time_t away_reply_timeout; /* Only send a 301 if this time passed. */
147
148        struct bee_user *bu;
149
150        const struct irc_user_funcs *f;
151} irc_user_t;
152
153struct irc_user_funcs {
154        gboolean (*privmsg)(irc_user_t *iu, const char *msg);
155        gboolean (*ctcp)(irc_user_t *iu, char * const* ctcp);
156};
157
158extern const struct irc_user_funcs irc_user_root_funcs;
159extern const struct irc_user_funcs irc_user_self_funcs;
160
161typedef enum {
162        IRC_CHANNEL_JOINED = 1, /* The user is currently in the channel. */
163        IRC_CHANNEL_TEMP = 2,   /* Erase the channel when the user leaves,
164                                   and don't save it. */
165
166        /* Hack: Set this flag right before jumping into IM when we expect
167           a call to imcb_chat_new(). */
168        IRC_CHANNEL_CHAT_PICKME = 0x10000,
169} irc_channel_flags_t;
170
171typedef struct irc_channel {
172        irc_t *irc;
173        char *name;
174        char mode[8];
175        int flags;
176
177        char *topic;
178        char *topic_who;
179        time_t topic_time;
180
181        GSList *users; /* struct irc_channel_user */
182        struct irc_user *last_target;
183        struct set *set;
184
185        GString *pastebuf; /* Paste buffer (combine lines into a multiline msg). */
186        guint pastebuf_timer;
187
188        const struct irc_channel_funcs *f;
189        void *data;
190} irc_channel_t;
191
192struct irc_channel_funcs {
193        gboolean (*privmsg)(irc_channel_t *ic, const char *msg);
194        gboolean (*join)(irc_channel_t *ic);
195        gboolean (*part)(irc_channel_t *ic, const char *msg);
196        gboolean (*topic)(irc_channel_t *ic, const char *new_topic);
197        gboolean (*invite)(irc_channel_t *ic, irc_user_t *iu);
198        void (*kick)(irc_channel_t *ic, irc_user_t *iu, const char *msg);
199
200        gboolean (*_init)(irc_channel_t *ic);
201        gboolean (*_free)(irc_channel_t *ic);
202};
203
204typedef enum {
205        IRC_CHANNEL_USER_OP = 1,
206        IRC_CHANNEL_USER_HALFOP = 2,
207        IRC_CHANNEL_USER_VOICE = 4,
208        IRC_CHANNEL_USER_NONE = 8,
209} irc_channel_user_flags_t;
210
211typedef struct irc_channel_user {
212        irc_user_t *iu;
213        int flags;
214} irc_channel_user_t;
215
216typedef enum {
217        IRC_CC_TYPE_DEFAULT  = 0x00001,
218        IRC_CC_TYPE_REST     = 0x00002, /* Still not implemented. */
219        IRC_CC_TYPE_GROUP    = 0x00004,
220        IRC_CC_TYPE_ACCOUNT  = 0x00008,
221        IRC_CC_TYPE_PROTOCOL = 0x00010,
222        IRC_CC_TYPE_MASK     = 0x000ff,
223        IRC_CC_TYPE_INVERT   = 0x00100,
224} irc_control_channel_type_t;
225
226struct irc_control_channel {
227        irc_control_channel_type_t type;
228        struct bee_group *group;
229        struct account *account;
230        struct prpl *protocol;
231        char modes[5];
232};
233
234extern const struct bee_ui_funcs irc_ui_funcs;
235
236typedef enum {
237        IRC_CDU_SILENT,
238        IRC_CDU_PART,
239        IRC_CDU_KICK,
240} irc_channel_del_user_type_t;
241
242/* These are a glued a little bit to the core/bee layer and a little bit to
243   IRC. The first user is OTR, and I guess at some point we'll get to shape
244   this a little bit more as other uses come up. */
245typedef struct irc_plugin {
246        /* Called at the end of irc_new(). Can be used to add settings, etc. */
247        gboolean (*irc_new)(irc_t *irc);
248        /* At the end of irc_free(). */
249        void (*irc_free)(irc_t *irc);
250
251        /* Problem with the following two functions is ordering if multiple
252           plugins are handling them. Let's keep fixing that problem for
253           whenever it becomes important. */
254
255        /* Called by bee_irc_user_privmsg_cb(). Return NULL if you want to
256           abort sending the msg. */
257        char* (*filter_msg_out)(irc_user_t * iu, char *msg, int flags);
258        /* Called by bee_irc_user_msg(). Return NULL if you swallowed the
259           message and don't want anything to go to the user. */
260        char* (*filter_msg_in)(irc_user_t * iu, char *msg, int flags);
261
262        /* From storage.c functions. Ideally these should not be used
263           and instead data should be stored in settings which will get
264           saved automatically. Consider these deprecated! */
265        void (*storage_load)(irc_t *irc);
266        void (*storage_save)(irc_t *irc);
267        void (*storage_remove)(const char *nick);
268} irc_plugin_t;
269
270extern GSList *irc_plugins; /* struct irc_plugin */
271
272/* irc.c */
273extern GSList *irc_connection_list;
274
275irc_t *irc_new(int fd);
276void irc_set_hosts(irc_t *irc, const struct sockaddr *remote_addr, const socklen_t remote_addrlen);
277void irc_abort(irc_t *irc, int immed, char *format, ...) G_GNUC_PRINTF(3, 4);
278void irc_free(irc_t *irc);
279void irc_setpass(irc_t *irc, const char *pass);
280
281void irc_process(irc_t *irc);
282char **irc_parse_line(char *line);
283char *irc_build_line(char **cmd);
284
285void irc_write(irc_t *irc, char *format, ...) G_GNUC_PRINTF(2, 3);
286void irc_write_all(int now, char *format, ...) G_GNUC_PRINTF(2, 3);
287void irc_vawrite(irc_t *irc, char *format, va_list params);
288
289void irc_flush(irc_t *irc);
290void irc_switch_fd(irc_t *irc, int fd);
291void irc_sync(irc_t *irc);
292void irc_desync(irc_t *irc);
293
294int irc_check_login(irc_t *irc);
295
296void irc_umode_set(irc_t *irc, const char *s, gboolean allow_priv);
297
298void register_irc_plugin(const struct irc_plugin *p);
299
300/* irc_channel.c */
301irc_channel_t *irc_channel_new(irc_t *irc, const char *name);
302irc_channel_t *irc_channel_by_name(irc_t *irc, const char *name);
303irc_channel_t *irc_channel_get(irc_t *irc, char *id);
304int irc_channel_free(irc_channel_t *ic);
305void irc_channel_free_soon(irc_channel_t *ic);
306int irc_channel_add_user(irc_channel_t *ic, irc_user_t *iu);
307int irc_channel_del_user(irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg);
308irc_channel_user_t *irc_channel_has_user(irc_channel_t *ic, irc_user_t *iu);
309struct irc_channel *irc_channel_with_user(irc_t *irc, irc_user_t *iu);
310int irc_channel_set_topic(irc_channel_t *ic, const char *topic, const irc_user_t *who);
311void irc_channel_user_set_mode(irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags);
312void irc_channel_set_mode(irc_channel_t *ic, const char *s);
313void irc_channel_auto_joins(irc_t *irc, struct account *acc);
314void irc_channel_printf(irc_channel_t *ic, char *format, ...) G_GNUC_PRINTF(2, 3);
315gboolean irc_channel_name_ok(const char *name);
316void irc_channel_name_strip(char *name);
317int irc_channel_name_cmp(const char *a_, const char *b_);
318char *irc_channel_name_gen(irc_t *irc, const char *name);
319gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name);
320void irc_channel_update_ops(irc_channel_t *ic, char *value);
321char irc_channel_user_get_prefix(irc_channel_user_t *icu);
322char *set_eval_irc_channel_ops(struct set *set, char *value);
323gboolean irc_channel_wants_user(irc_channel_t *ic, irc_user_t *iu);
324
325/* irc_commands.c */
326void irc_exec(irc_t *irc, char **cmd);
327
328/* irc_send.c */
329void irc_send_num(irc_t *irc, int code, char *format, ...) G_GNUC_PRINTF(3, 4);
330void irc_send_login(irc_t *irc);
331void irc_send_motd(irc_t *irc);
332const char *irc_user_msgdest(irc_user_t *iu);
333void irc_rootmsg(irc_t *irc, char *format, ...) G_GNUC_PRINTF(2, 3);
334void irc_usermsg(irc_user_t *iu, char *format, ...) G_GNUC_PRINTF(2, 3);
335void irc_usernotice(irc_user_t *iu, char *format, ...) G_GNUC_PRINTF(2, 3);
336void irc_send_join(irc_channel_t *ic, irc_user_t *iu);
337void irc_send_part(irc_channel_t *ic, irc_user_t *iu, const char *reason);
338void irc_send_quit(irc_user_t *iu, const char *reason);
339void irc_send_kick(irc_channel_t *ic, irc_user_t *iu, irc_user_t *kicker, const char *reason);
340void irc_send_names(irc_channel_t *ic);
341void irc_send_topic(irc_channel_t *ic, gboolean topic_change);
342void irc_send_whois(irc_user_t *iu);
343void irc_send_who(irc_t *irc, GSList *l, const char *channel);
344void irc_send_msg(irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix);
345void irc_send_msg_raw(irc_user_t *iu, const char *type, const char *dst, const char *msg);
346void irc_send_msg_f(irc_user_t *iu, const char *type, const char *dst, const char *format, ...) G_GNUC_PRINTF(4, 5);
347void irc_send_nick(irc_user_t *iu, const char *new_nick);
348void irc_send_channel_user_mode_diff(irc_channel_t *ic, irc_user_t *iu,
349                                     irc_channel_user_flags_t old_flags, irc_channel_user_flags_t new_flags);
350void irc_send_invite(irc_user_t *iu, irc_channel_t *ic);
351void irc_send_cap(irc_t *irc, char *subcommand, char *body);
352void irc_send_away_notify(irc_user_t *iu);
353
354/* irc_user.c */
355irc_user_t *irc_user_new(irc_t *irc, const char *nick);
356int irc_user_free(irc_t *irc, irc_user_t *iu);
357irc_user_t *irc_user_by_name(irc_t *irc, const char *nick);
358int irc_user_set_nick(irc_user_t *iu, const char *new_nick);
359gint irc_user_cmp(gconstpointer a_, gconstpointer b_);
360const char *irc_user_get_away(irc_user_t *iu);
361void irc_user_quit(irc_user_t *iu, const char *msg);
362
363/* irc_util.c */
364char *set_eval_timezone(struct set *set, char *value);
365char *irc_format_timestamp(irc_t *irc, time_t msg_ts);
366char *set_eval_self_messages(struct set *set, char *value);
367
368/* irc_im.c */
369void bee_irc_channel_update(irc_t *irc, irc_channel_t *ic, irc_user_t *iu);
370void bee_irc_user_nick_reset(irc_user_t *iu);
371
372/* irc_cap.c */
373void irc_cmd_cap(irc_t *irc, char **cmd);
374
375#endif
Note: See TracBrowser for help on using the repository browser.