unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
watch.c (11597B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/watch.c 3 * (C) 2005 The UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include "unrealircd.h" 24 25 #define MSG_WATCH "WATCH" 26 27 CMD_FUNC(cmd_watch); 28 int watch_user_quit(Client *client, MessageTag *mtags, const char *comment); 29 int watch_away(Client *client, MessageTag *mtags, const char *reason, int already_as_away); 30 int watch_nickchange(Client *client, MessageTag *mtags, const char *newnick); 31 int watch_post_nickchange(Client *client, MessageTag *mtags, const char *oldnick); 32 int watch_user_connect(Client *client); 33 int watch_notification(Client *client, Watch *watch, Link *lp, int event); 34 35 ModuleHeader MOD_HEADER 36 = { 37 "watch", 38 "5.0", 39 "command /watch", 40 "UnrealIRCd Team", 41 "unrealircd-6", 42 }; 43 44 MOD_INIT() 45 { 46 MARK_AS_OFFICIAL_MODULE(modinfo); 47 48 CommandAdd(modinfo->handle, MSG_WATCH, cmd_watch, 1, CMD_USER); 49 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, watch_user_quit); 50 HookAdd(modinfo->handle, HOOKTYPE_REMOTE_QUIT, 0, watch_user_quit); 51 HookAdd(modinfo->handle, HOOKTYPE_AWAY, 0, watch_away); 52 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_NICKCHANGE, 0, watch_nickchange); 53 HookAdd(modinfo->handle, HOOKTYPE_REMOTE_NICKCHANGE, 0, watch_nickchange); 54 HookAdd(modinfo->handle, HOOKTYPE_POST_LOCAL_NICKCHANGE, 0, watch_post_nickchange); 55 HookAdd(modinfo->handle, HOOKTYPE_POST_REMOTE_NICKCHANGE, 0, watch_post_nickchange); 56 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, watch_user_connect); 57 HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, 0, watch_user_connect); 58 59 return MOD_SUCCESS; 60 } 61 62 MOD_LOAD() 63 { 64 return MOD_SUCCESS; 65 } 66 67 MOD_UNLOAD() 68 { 69 return MOD_SUCCESS; 70 } 71 72 /* 73 * RPL_NOWON - Online at the moment (Successfully added to WATCH-list) 74 * RPL_NOWOFF - Offline at the moement (Successfully added to WATCH-list) 75 */ 76 static void show_watch(Client *client, char *name, int awaynotify) 77 { 78 Client *target; 79 80 if ((target = find_user(name, NULL))) 81 { 82 if (awaynotify && target->user->away) 83 { 84 sendnumeric(client, RPL_NOWISAWAY, 85 target->name, target->user->username, 86 IsHidden(target) ? target->user->virthost : target->user->realhost, 87 (long long)target->user->away_since); 88 return; 89 } 90 91 sendnumeric(client, RPL_NOWON, 92 target->name, target->user->username, 93 IsHidden(target) ? target->user->virthost : target->user->realhost, 94 (long long)target->lastnick); 95 } 96 else 97 { 98 sendnumeric(client, RPL_NOWOFF, name, "*", "*", 0LL); 99 } 100 } 101 102 /* 103 * RPL_WATCHOFF - Successfully removed from WATCH-list. 104 */ 105 static void show_watch_removed(Client *client, char *name) 106 { 107 Client *target; 108 109 if ((target = find_user(name, NULL))) 110 { 111 sendnumeric(client, RPL_WATCHOFF, 112 target->name, target->user->username, 113 IsHidden(target) ? target->user->virthost : target->user->realhost, 114 (long long)target->lastnick); 115 } 116 else 117 { 118 sendnumeric(client, RPL_WATCHOFF, name, "*", "*", 0LL); 119 } 120 } 121 122 #define WATCHES(client) (moddata_local_client(client, watchCounterMD).i) 123 #define WATCH(client) (moddata_local_client(client, watchListMD).ptr) 124 125 /* 126 * cmd_watch 127 */ 128 CMD_FUNC(cmd_watch) 129 { 130 char request[BUFSIZE]; 131 char buf[BUFSIZE]; 132 Client *target; 133 char *s, *user; 134 char *p = NULL, *def = "l"; 135 int awaynotify = 0; 136 int did_l=0, did_s=0; 137 138 if (!MyUser(client)) 139 return; 140 141 if (parc < 2) 142 { 143 /* 144 * Default to 'l' - list who's currently online 145 */ 146 parc = 2; 147 parv[1] = def; 148 } 149 150 151 ModDataInfo *watchCounterMD = findmoddata_byname("watchCount", MODDATATYPE_LOCAL_CLIENT); 152 ModDataInfo *watchListMD = findmoddata_byname("watchList", MODDATATYPE_LOCAL_CLIENT); 153 154 if (!watchCounterMD || !watchListMD) 155 { 156 unreal_log(ULOG_ERROR, "watch", "WATCH_BACKEND_MISSING", NULL, 157 "[watch] moddata unavailable. Is the 'watch-backend' module loaded?"); 158 sendnotice(client, "WATCH command is not available at this moment. Please try again later."); 159 return; 160 } 161 162 strlcpy(request, parv[1], sizeof(request)); 163 for (s = strtoken(&p, request, " "); s; s = strtoken(&p, NULL, " ")) 164 { 165 if ((user = strchr(s, '!'))) 166 *user++ = '\0'; /* Not used */ 167 168 if (!strcmp(s, "A") && WATCH_AWAY_NOTIFICATION) 169 awaynotify = 1; 170 171 /* 172 * Prefix of "+", they want to add a name to their WATCH 173 * list. 174 */ 175 if (*s == '+') 176 { 177 if (!*(s+1)) 178 continue; 179 if (do_nick_name(s + 1)) 180 { 181 if (WATCHES(client) >= MAXWATCH) 182 { 183 sendnumeric(client, ERR_TOOMANYWATCH, s + 1); 184 continue; 185 } 186 187 watch_add(s + 1, client, 188 WATCH_FLAG_TYPE_WATCH | (awaynotify ? WATCH_FLAG_AWAYNOTIFY : 0) 189 ); 190 } 191 192 show_watch(client, s + 1, awaynotify); 193 continue; 194 } 195 196 /* 197 * Prefix of "-", coward wants to remove somebody from their 198 * WATCH list. So do it. :-) 199 */ 200 if (*s == '-') 201 { 202 if (!*(s+1)) 203 continue; 204 watch_del(s + 1, client, WATCH_FLAG_TYPE_WATCH); 205 show_watch_removed(client, s + 1); 206 continue; 207 } 208 209 /* 210 * Fancy "C" or "c", they want to nuke their WATCH list and start 211 * over, so be it. 212 */ 213 if (*s == 'C' || *s == 'c') 214 { 215 watch_del_list(client, WATCH_FLAG_TYPE_WATCH); 216 continue; 217 } 218 219 /* 220 * Now comes the fun stuff, "S" or "s" returns a status report of 221 * their WATCH list. I imagine this could be CPU intensive if its 222 * done alot, perhaps an auto-lag on this? 223 */ 224 if ((*s == 'S' || *s == 's') && !did_s) 225 { 226 Link *lp; 227 Watch *watch; 228 int count = 0; 229 230 did_s = 1; 231 232 /* 233 * Send a list of how many users they have on their WATCH list 234 * and how many WATCH lists they are on. This will also include 235 * other WATCH types if present - we're not checking for 236 * WATCH_FLAG_TYPE_*. 237 */ 238 watch = watch_get(client->name); 239 if (watch) 240 for (lp = watch->watch, count = 1; 241 (lp = lp->next); count++) 242 ; 243 sendnumeric(client, RPL_WATCHSTAT, WATCHES(client), count); 244 245 /* 246 * Send a list of everybody in their WATCH list. Be careful 247 * not to buffer overflow. 248 */ 249 lp = WATCH(client); 250 *buf = '\0'; 251 count = strlen(client->name) + strlen(me.name) + 10; 252 while (lp) 253 { 254 if (!(lp->flags & WATCH_FLAG_TYPE_WATCH)) 255 { 256 lp = lp->next; 257 continue; /* this one is not ours */ 258 } 259 if (count + strlen(lp->value.wptr->nick) + 1 > 260 BUFSIZE - 2) 261 { 262 sendnumeric(client, RPL_WATCHLIST, buf); 263 *buf = '\0'; 264 count = strlen(client->name) + strlen(me.name) + 10; 265 } 266 strcat(buf, " "); 267 strcat(buf, lp->value.wptr->nick); 268 count += (strlen(lp->value.wptr->nick) + 1); 269 270 lp = lp->next; 271 } 272 if (*buf) 273 /* anything to send */ 274 sendnumeric(client, RPL_WATCHLIST, buf); 275 276 sendnumeric(client, RPL_ENDOFWATCHLIST, *s); 277 continue; 278 } 279 280 /* 281 * Well that was fun, NOT. Now they want a list of everybody in 282 * their WATCH list AND if they are online or offline? Sheesh, 283 * greedy arn't we? 284 */ 285 if ((*s == 'L' || *s == 'l') && !did_l) 286 { 287 Link *lp = WATCH(client); 288 289 did_l = 1; 290 291 while (lp) 292 { 293 if (!(lp->flags & WATCH_FLAG_TYPE_WATCH)) 294 { 295 lp = lp->next; 296 continue; /* this one is not ours */ 297 } 298 if ((target = find_user(lp->value.wptr->nick, NULL))) 299 { 300 sendnumeric(client, RPL_NOWON, target->name, 301 target->user->username, 302 IsHidden(target) ? target->user-> 303 virthost : target->user->realhost, 304 (long long)target->lastnick); 305 } 306 /* 307 * But actually, only show them offline if its a capital 308 * 'L' (full list wanted). 309 */ 310 else if (isupper(*s)) 311 sendnumeric(client, RPL_NOWOFF, 312 lp->value.wptr->nick, "*", "*", 313 (long long)lp->value.wptr->lasttime); 314 lp = lp->next; 315 } 316 317 sendnumeric(client, RPL_ENDOFWATCHLIST, *s); 318 319 continue; 320 } 321 322 /* 323 * Hmm.. unknown prefix character.. Ignore it. :-) 324 */ 325 } 326 } 327 328 int watch_user_quit(Client *client, MessageTag *mtags, const char *comment) 329 { 330 if (IsUser(client)) 331 watch_check(client, WATCH_EVENT_OFFLINE, watch_notification); 332 return 0; 333 } 334 335 int watch_away(Client *client, MessageTag *mtags, const char *reason, int already_as_away) 336 { 337 if (reason) 338 watch_check(client, already_as_away ? WATCH_EVENT_REAWAY : WATCH_EVENT_AWAY, watch_notification); 339 else 340 watch_check(client, WATCH_EVENT_NOTAWAY, watch_notification); 341 342 return 0; 343 } 344 345 int watch_nickchange(Client *client, MessageTag *mtags, const char *newnick) 346 { 347 watch_check(client, WATCH_EVENT_OFFLINE, watch_notification); 348 349 return 0; 350 } 351 352 int watch_post_nickchange(Client *client, MessageTag *mtags, const char *oldnick) 353 { 354 watch_check(client, WATCH_EVENT_ONLINE, watch_notification); 355 356 return 0; 357 } 358 359 int watch_user_connect(Client *client) 360 { 361 watch_check(client, WATCH_EVENT_ONLINE, watch_notification); 362 363 return 0; 364 } 365 366 int watch_notification(Client *client, Watch *watch, Link *lp, int event) 367 { 368 int awaynotify = 0; 369 370 if (!(lp->flags & WATCH_FLAG_TYPE_WATCH)) 371 return 0; 372 373 if ((event == WATCH_EVENT_AWAY) || (event == WATCH_EVENT_NOTAWAY) || (event == WATCH_EVENT_REAWAY)) 374 awaynotify = 1; 375 376 if (!awaynotify) 377 { 378 if (event == WATCH_EVENT_OFFLINE) 379 { 380 sendnumeric(lp->value.client, RPL_LOGOFF, 381 client->name, 382 (IsUser(client) ? client->user->username : "<N/A>"), 383 (IsUser(client) ? (IsHidden(client) ? client->user->virthost : client->user->realhost) : "<N/A>"), 384 (long long)watch->lasttime); 385 } else { 386 sendnumeric(lp->value.client, RPL_LOGON, 387 client->name, 388 (IsUser(client) ? client->user->username : "<N/A>"), 389 (IsUser(client) ? (IsHidden(client) ? client->user->virthost : client->user->realhost) : "<N/A>"), 390 (long long)watch->lasttime); 391 } 392 } 393 else 394 { 395 /* AWAY or UNAWAY */ 396 if (!(lp->flags & WATCH_FLAG_AWAYNOTIFY)) 397 return 0; /* skip away/unaway notification for users not interested in them */ 398 399 if (event == WATCH_EVENT_NOTAWAY) 400 { 401 sendnumeric(lp->value.client, RPL_NOTAWAY, 402 client->name, 403 (IsUser(client) ? client->user->username : "<N/A>"), 404 (IsUser(client) ? (IsHidden(client) ? client->user->virthost : client->user->realhost) : "<N/A>"), 405 (long long)client->user->away_since); 406 } else 407 if (event == RPL_GONEAWAY) 408 { 409 sendnumeric(lp->value.client, RPL_GONEAWAY, 410 client->name, 411 (IsUser(client) ? client->user->username : "<N/A>"), 412 (IsUser(client) ? (IsHidden(client) ? client->user->virthost : client->user->realhost) : "<N/A>"), 413 (long long)client->user->away_since, 414 client->user->away); 415 } else 416 if (event == RPL_REAWAY) 417 { 418 sendnumeric(lp->value.client, RPL_REAWAY, 419 client->name, 420 (IsUser(client) ? client->user->username : "<N/A>"), 421 (IsUser(client) ? (IsHidden(client) ? client->user->virthost : client->user->realhost) : "<N/A>"), 422 (long long)client->user->away_since, 423 client->user->away); 424 } 425 } 426 427 return 0; 428 } 429