Merge fix for logging of mode changes by charly.
[jelmer/ctrlproxy.git] / src / auto_away.c
1 /* 
2         ctrlproxy: A modular IRC proxy
3         (c) 2002-2003 Jelmer Vernooij <jelmer@nl.linux.org>
4
5         This program is free software; you can redistribute it and/or modify
6         it under the terms of the GNU General Public License as published by
7         the Free Software Foundation; either version 3 of the License, or
8         (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program; if not, write to the Free Software
17         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /* TODO This breaks:
21  *    * One client connected. User does /AWAY msg.
22  *    * Client quits.
23  *    * Client rejoins. If client_limit=0, the connection is set as not away
24  *      => there should be distinction between auto-away and client-away?
25  */
26
27 #include "ctrlproxy.h"
28 #include "local.h"
29 #include <string.h>
30
31 /**
32  * State data for auto-away.
33  */
34 struct auto_away_data {
35         struct auto_away_config *config;
36         int max_idle_time;
37         time_t last_message;
38         guint timeout_id;
39         struct global *global;
40 };
41
42 static gboolean check_time(gpointer user_data) 
43 {
44         struct auto_away_data *d = (struct auto_away_data *)user_data;
45
46         if (time(NULL) - d->last_message > d->max_idle_time) {
47                 GList *sl;
48                 for (sl = d->global->networks; sl; sl = sl->next) {
49                         struct irc_network *s = (struct irc_network *)sl->data;
50                         if (s->connection.state == NETWORK_CONNECTION_STATE_MOTD_RECVD &&
51                                 s->external_state != NULL && !s->external_state->is_away && 
52                             (d->config->client_limit < 0 || g_list_length(s->clients) <= d->config->client_limit)) {
53                                 network_send_args(s, "AWAY", 
54                                                                   d->config->message != NULL?d->config->message:"Auto Away", 
55                                                                   NULL);
56                                 if (d->config->nick != NULL) {
57                                         network_send_args(s, "NICK", d->config->nick, NULL);
58                                 }
59                         }
60                 }
61         }
62
63         return TRUE;
64 }
65
66 static gboolean log_data(struct irc_network *n, const struct irc_line *l, 
67                                                  enum data_direction dir, void *userdata) 
68 {
69         struct auto_away_data *d = userdata;
70         GList *sl;
71
72         if (dir == TO_SERVER && !g_strcasecmp(l->args[0], "AWAY")) {
73                 d->last_message = time(NULL);
74         }
75
76         if (dir == TO_SERVER &&  
77            (!g_strcasecmp(l->args[0], "PRIVMSG") || 
78                 !g_strcasecmp(l->args[0], "NOTICE"))) {
79                 d->last_message = time(NULL);
80                 for (sl = d->global->networks; sl; sl = sl->next) {
81                         struct irc_network *s = (struct irc_network *)sl->data;
82                         if (s->connection.state == NETWORK_CONNECTION_STATE_MOTD_RECVD &&
83                                 s->external_state != NULL && s->external_state->is_away)
84                                 network_send_args(s, "AWAY", NULL);
85                 }
86         }
87         return TRUE;
88 }
89
90 static gboolean new_client(struct irc_client *c, void *userdata) 
91 {
92         struct auto_away_data *d = userdata;
93
94         if (d->config->client_limit >= 0 && d->config->client_limit < g_list_length(c->network->clients)+1)
95                 network_send_args(c->network, "AWAY", NULL);
96
97         return TRUE;
98 }
99
100 static void lose_client(struct irc_client *c, void *userdata) 
101 {
102         struct auto_away_data *d = userdata;
103
104         if (d->config->client_limit >= 0 && d->config->client_limit >= g_list_length(c->network->clients))
105                 network_send_args(c->network, "AWAY", 
106                                                                   d->config->message != NULL?d->config->message:"Auto Away", 
107                                                                   NULL);
108 }
109
110 void auto_away_add(struct global *global, struct auto_away_config *config)
111 {
112         struct auto_away_data *d = g_new0(struct auto_away_data, 1);
113
114         d->config = config;
115         d->last_message = time(NULL);
116         d->max_idle_time = config->max_idle_time != -1?config->max_idle_time:AUTO_AWAY_DEFAULT_TIME;
117         d->global = global;
118         if (d->max_idle_time >= 30)
119                 d->timeout_id = g_timeout_add(1000, check_time, d);
120         else
121                 log_global(LOG_WARNING, "Ignoring auto-away time %d because it is too low", d->max_idle_time);
122         add_new_client_hook("auto-away", new_client, d);
123         add_lose_client_hook("auto-away", lose_client, d);
124         add_server_filter("auto-away", log_data, d, -1);
125 }