unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
monitor.c (6351B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/monitor.c 3 * (C) 2021 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_MONITOR "MONITOR" 26 27 #define STR_HELPER(x) #x 28 #define STR(x) STR_HELPER(x) 29 30 CMD_FUNC(cmd_monitor); 31 char *monitor_isupport_param(void); 32 int monitor_nickchange(Client *client, MessageTag *mtags, const char *newnick); 33 int monitor_post_nickchange(Client *client, MessageTag *mtags, const char *oldnick); 34 int monitor_quit(Client *client, MessageTag *mtags, const char *comment); 35 int monitor_connect(Client *client); 36 int monitor_notification(Client *client, Watch *watch, Link *lp, int event); 37 38 ModuleHeader MOD_HEADER 39 = { 40 "monitor", 41 "5.0", 42 "command /monitor", 43 "UnrealIRCd Team", 44 "unrealircd-6", 45 }; 46 47 MOD_INIT() 48 { 49 MARK_AS_OFFICIAL_MODULE(modinfo); 50 51 CommandAdd(modinfo->handle, MSG_MONITOR, cmd_monitor, 2, CMD_USER); 52 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_NICKCHANGE, 0, monitor_nickchange); 53 HookAdd(modinfo->handle, HOOKTYPE_REMOTE_NICKCHANGE, 0, monitor_nickchange); 54 HookAdd(modinfo->handle, HOOKTYPE_POST_LOCAL_NICKCHANGE, 0, monitor_post_nickchange); 55 HookAdd(modinfo->handle, HOOKTYPE_POST_REMOTE_NICKCHANGE, 0, monitor_post_nickchange); 56 HookAdd(modinfo->handle, HOOKTYPE_REMOTE_QUIT, 0, monitor_quit); 57 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, monitor_quit); 58 HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, monitor_connect); 59 HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, 0, monitor_connect); 60 61 return MOD_SUCCESS; 62 } 63 64 MOD_LOAD() 65 { 66 ISupportAdd(modinfo->handle, "MONITOR", monitor_isupport_param()); 67 return MOD_SUCCESS; 68 } 69 70 MOD_UNLOAD() 71 { 72 return MOD_SUCCESS; 73 } 74 75 char *monitor_isupport_param(void) 76 { 77 /* i find it unlikely for a client to use WATCH and MONITOR at the same time, so keep a single limit for both */ 78 return STR(MAXWATCH); 79 } 80 81 int monitor_nickchange(Client *client, MessageTag *mtags, const char *newnick) 82 { 83 if (!smycmp(client->name, newnick)) // new nick is same as old one, maybe the case changed 84 return 0; 85 86 watch_check(client, WATCH_EVENT_OFFLINE, monitor_notification); 87 return 0; 88 } 89 90 int monitor_post_nickchange(Client *client, MessageTag *mtags, const char *oldnick) 91 { 92 if (!smycmp(client->name, oldnick)) // new nick is same as old one, maybe the case changed 93 return 0; 94 95 watch_check(client, WATCH_EVENT_ONLINE, monitor_notification); 96 return 0; 97 } 98 99 int monitor_quit(Client *client, MessageTag *mtags, const char *comment) 100 { 101 watch_check(client, WATCH_EVENT_OFFLINE, monitor_notification); 102 return 0; 103 } 104 105 int monitor_connect(Client *client) 106 { 107 watch_check(client, WATCH_EVENT_ONLINE, monitor_notification); 108 return 0; 109 } 110 111 int monitor_notification(Client *client, Watch *watch, Link *lp, int event) 112 { 113 if (!(lp->flags & WATCH_FLAG_TYPE_MONITOR)) 114 return 0; 115 116 switch (event) 117 { 118 case WATCH_EVENT_ONLINE: 119 sendnumeric(lp->value.client, RPL_MONONLINE, client->name, client->user->username, GetHost(client)); 120 break; 121 case WATCH_EVENT_OFFLINE: 122 sendnumeric(lp->value.client, RPL_MONOFFLINE, client->name); 123 break; 124 default: 125 break; /* may be handled by other modules */ 126 } 127 128 return 0; 129 } 130 131 void send_status(Client *client, MessageTag *recv_mtags, const char *nick) 132 { 133 MessageTag *mtags = NULL; 134 Client *user; 135 user = find_user(nick, NULL); 136 new_message(client, recv_mtags, &mtags); 137 if (!user){ 138 sendnumeric(client, RPL_MONOFFLINE, nick); 139 } else { 140 sendnumeric(client, RPL_MONONLINE, user->name, user->user->username, GetHost(user)); 141 } 142 free_message_tags(mtags); 143 } 144 145 #define WATCHES(client) (moddata_local_client(client, watchCounterMD).i) 146 #define WATCH(client) (moddata_local_client(client, watchListMD).ptr) 147 148 CMD_FUNC(cmd_monitor) 149 { 150 char request[BUFSIZE]; 151 char cmd; 152 char *s, *p = NULL; 153 int i; 154 int toomany = 0; 155 Link *lp; 156 157 if (!MyUser(client)) 158 return; 159 160 if (parc < 2 || BadPtr(parv[1])) 161 cmd = 'l'; 162 else 163 cmd = tolower(*parv[1]); 164 165 ModDataInfo *watchCounterMD = findmoddata_byname("watchCount", MODDATATYPE_LOCAL_CLIENT); 166 ModDataInfo *watchListMD = findmoddata_byname("watchList", MODDATATYPE_LOCAL_CLIENT); 167 168 if (!watchCounterMD || !watchListMD) 169 { 170 unreal_log(ULOG_ERROR, "monitor", "WATCH_BACKEND_MISSING", NULL, 171 "[monitor] moddata unavailable. Is the 'watch-backend' module loaded?"); 172 sendnotice(client, "MONITOR command is not available at this moment. Please try again later."); 173 return; 174 } 175 176 switch(cmd) 177 { 178 case 'c': 179 watch_del_list(client, WATCH_FLAG_TYPE_MONITOR); 180 break; 181 case 'l': 182 lp = WATCH(client); 183 while (lp) 184 { 185 if (!(lp->flags & WATCH_FLAG_TYPE_MONITOR)) 186 { 187 lp = lp->next; 188 continue; /* this one is not ours */ 189 } 190 sendnumeric(client, RPL_MONLIST, lp->value.wptr->nick); 191 lp = lp->next; 192 } 193 194 sendnumeric(client, RPL_ENDOFMONLIST); 195 break; 196 case 's': 197 lp = WATCH(client); 198 while (lp) 199 { 200 if (!(lp->flags & WATCH_FLAG_TYPE_MONITOR)) 201 { 202 lp = lp->next; 203 continue; /* this one is not ours */ 204 } 205 send_status(client, recv_mtags, lp->value.wptr->nick); 206 lp = lp->next; 207 } 208 break; 209 case '-': 210 case '+': 211 if (parc < 3 || BadPtr(parv[2])) 212 return; 213 strlcpy(request, parv[2], sizeof(request)); 214 for (s = strtoken(&p, request, ","); s; s = strtoken(&p, NULL, ",")) 215 { 216 if (cmd == '-') { 217 watch_del(s, client, WATCH_FLAG_TYPE_MONITOR); 218 } else { 219 if (WATCHES(client) >= MAXWATCH) 220 { 221 sendnumeric(client, ERR_MONLISTFULL, MAXWATCH, s); 222 continue; 223 } 224 if (do_nick_name(s)) 225 watch_add(s, client, WATCH_FLAG_TYPE_MONITOR); 226 send_status(client, recv_mtags, s); 227 } 228 } 229 break; 230 } 231 } 232