]> jfr.im git - irc/quakenet/newserv.git/blame - noperserv/noperserv.c
Implement authext/user support for NOperserv.
[irc/quakenet/newserv.git] / noperserv / noperserv.c
CommitLineData
3e3692bf
CP
1/*
2 * NOperserv v0.01
3 *
4 * A replacement for Germania's ageing Operservice2
5 *
6 * Copyright (C) 2005 Chris Porter.
7 */
8
9#include "../localuser/localuser.h"
10#include "../lib/irc_string.h"
d7a70850 11#include "../lib/strlfunc.h"
87698d77 12#include "../lib/version.h"
fb17e427 13#include "../authext/authext.h"
3e3692bf
CP
14#include "noperserv.h"
15#include "noperserv_db.h"
16#include "noperserv_hooks.h"
17#include "noperserv_policy.h"
18
19#include <stdio.h>
20#include <string.h>
21#include <stdarg.h>
22
70b0a4e5 23MODULE_VERSION("");
87698d77 24
3e3692bf
CP
25#define FLAGBUFLEN 100
26
27#define NO_FOUND_NICKNAME 1
28#define NO_FOUND_AUTHNAME 2
29
30const flag no_commandflags[] = {
31 { 'o', __NO_OPER },
32 { 't', __NO_TRUST },
33 { 's', __NO_STAFF },
34 { 'S', __NO_SEC },
35 { 'd', __NO_DEVELOPER },
36 { 'L', __NO_LEGACY },
37 { 'O', __NO_OPERED },
38 { 'r', __NO_AUTHED },
39 { 'R', __NO_ACCOUNT },
3f5ead93 40 { 'Y', __NO_RELAY },
3e3692bf
CP
41 { '\0', 0 }
42 };
43
44const flag no_userflags[] = {
45 { 'o', __NO_OPER },
46 { 't', __NO_TRUST },
47 { 's', __NO_STAFF },
48 { 'S', __NO_SEC },
49 { 'd', __NO_DEVELOPER },
3f5ead93 50 { 'Y', __NO_RELAY },
3e3692bf
CP
51 { '\0', 0 }
52 };
53
54const flag no_noticeflags[] = {
55 { 'm', NL_MANAGEMENT }, /* hello, password, userflags, noticeflags */
56 { 't', NL_TRUSTS }, /* trust stuff... */
a50e1bf1
CP
57 { 'k', NL_KICKKILLS }, /* KICK/KILL commands */
58 { 'I', NL_MISC }, /* misc commands */
3e3692bf
CP
59 { 'g', NL_GLINES }, /* GLINE commands */
60 { 'h', NL_HITS }, /* Where a gline or kill is set automatically by the bot */
61 { 'c', NL_CLONING }, /* Clone detection */
62 { 'C', NL_CLEARCHAN }, /* When someone clearchans */
63 { 'f', NL_FAKEUSERS }, /* Fakeuser addition */
64 { 'b', NL_BROADCASTS }, /* Broadcast/mbroadcast/sbroadcast */
65 { 'o', NL_OPERATIONS }, /* insmod/rmmod/etc */
66 { 'O', NL_OPERING }, /* when someone opers */
67 { 'n', NL_NOTICES }, /* turn off to receive notices instead of privmsgs */
68 { 'A', NL_ALL_COMMANDS }, /* all commands sent */
69 { '\0', 0 }
70 };
71
72int noperserv_hello(void *sender, int cargc, char **cargv);
73int noperserv_noticeflags(void *sender, int cargc, char **cargv);
74int noperserv_userflags(void *sender, int cargc, char **cargv);
75int noperserv_deluser(void *sender, int cargc, char **cargv);
76void noperserv_oper_detection(int hooknum, void *arg);
bb4b25ee 77void noperserv_reply(nick *np, char *format, ...) __attribute__ ((format (printf, 2, 3)));
3e3692bf 78
7a32ca6e
CP
79int init = 0;
80
3e3692bf 81void _init() {
7a32ca6e
CP
82 if(!noperserv_load_db())
83 return;
3e3692bf 84
7078aa50 85 noperserv_ext = registerauthnameext("noperserv", 1);
3e3692bf
CP
86
87 noperserv_setup_hooks();
88
89 registercontrolhelpcmd("hello", NO_OPERED | NO_AUTHED, 1, &noperserv_hello, "Syntax: HELLO ?nickname|#authname?\nCreates an account on the service for the specified nick, or if one isn't supplied, your nickname.");
cc3768c4
CP
90 registercontrolhelpcmd("userflags", NO_ACCOUNT, 2, &noperserv_userflags,
91 "Syntax: USERFLAGS <nickname|#authname> ?modifications?\n"
92 " Views and modifies user permissions.\n"
93 " If no nickname or authname is supplied, you are substituted for it.\n"
94 " If no flags are supplied, flags are just displayed instead of modified."
95 " Flags:\n"
96 " +o: Operator\n"
97 " +s: Staff member\n"
98 " +S: Security team member\n"
99 " +d: NOperserv developer\n"
100 " +t: Trust queue worker\n"
3f5ead93 101 " +Y: Relay\n"
cc3768c4
CP
102 " Additional flags may show up in SHOWCOMMANDS but are not userflags as such:\n"
103 " +r: Authed user\n"
a50e1bf1
CP
104 " +R: Registered NOperserv user\n"
105 " +O: Must be /OPER'ed\n"
cc3768c4
CP
106 " +L: Legacy command\n"
107 );
3e3692bf
CP
108 registercontrolhelpcmd("noticeflags", NO_ACCOUNT, 1, &noperserv_noticeflags,
109 "Syntax: NOTICEFLAGS ?(nickname|#authname)|flags?\n"
110 " This command can view and modify your own notice flags, and view that of other users.\n"
111 " Flags:\n"
112 " +m: Management (hello, password, userflags, noticeflags)\n"
113 " +t: Trusts\n"
a50e1bf1 114 " +k: KICK/KILL commands\n"
3e3692bf 115 " +g: GLINE commands\n"
35070c19 116 " +h: Shows when glines are set by code (hits)\n"
3e3692bf
CP
117 " +c: Clone information\n"
118 " +C: CLEARCHAN command\n"
cc3768c4 119 " +f: FAKEUSER commands\n"
3e3692bf
CP
120 " +b: BROADCAST commands\n"
121 " +o: Operation commands, such as insmod, rmmod, die, etc\n"
122 " +O: /OPER\n"
9aacd544 123 " +I: Misc commands (resync, etc)\n"
3e3692bf 124 " +n: Sends notices instead of privmsgs\n"
cc3768c4 125 " +A: Every single command sent to the service (spammy)\n"
3e3692bf
CP
126 );
127
128 registercontrolhelpcmd("deluser", NO_OPERED | NO_ACCOUNT, 2, &noperserv_deluser, "Syntax: DELUSER <nickname|#authname>\nDeletes the specified user.");
129 registerhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
7a32ca6e
CP
130
131 init = 1;
3e3692bf
CP
132}
133
134#ifdef BROKEN_DLCLOSE
135void __fini() {
136#else
137void _fini() {
138#endif
7a32ca6e
CP
139 if(!init)
140 return;
141
3e3692bf
CP
142 deregisterhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
143
144 deregistercontrolcmd("noticeflags", &noperserv_noticeflags);
145 deregistercontrolcmd("userflags", &noperserv_userflags);
146 deregistercontrolcmd("noticeflags", &noperserv_noticeflags);
7821bd5e
CP
147 deregistercontrolcmd("hello", &noperserv_hello);
148 deregistercontrolcmd("deluser", &noperserv_deluser);
3e3692bf
CP
149
150 noperserv_cleanup_hooks();
151
152 noperserv_cleanup_db();
153
7078aa50 154 releaseauthnameext(noperserv_ext);
3e3692bf
CP
155}
156
157/* @test */
158int noperserv_hello(void *sender, int cargc, char **cargv) {
7078aa50 159 authname *newaccount = NULL;
3e3692bf 160 no_autheduser *au;
3e3692bf
CP
161 nick *np = (nick *)sender, *np2, *target = NULL;
162
163 if(cargc == 0) {
7078aa50 164 newaccount = np->auth;
3e3692bf
CP
165 } else {
166 if(cargv[0][0] == '#') {
7b1a4a73 167 authname *a = getauthbyname(cargv[0] + 1);
fb17e427 168 if(!a) {
3e3692bf
CP
169 controlreply(np, "Cannot find anyone with that authname on the network.");
170 return CMD_ERROR;
171 }
7078aa50 172 newaccount = a;
3e3692bf
CP
173 } else {
174 target = getnickbynick(cargv[0]);
175 if(!target) {
176 controlreply(np, "Supplied nickname is not on the network.");
177 return CMD_ERROR;
178 }
7078aa50 179 newaccount = target->auth;
3e3692bf
CP
180 }
181 }
7078aa50
GB
182 if(!newaccount) {
183 controlreply(np, "Supplied user is not authed with the network.");
184 return CMD_ERROR;
185 }
3e3692bf
CP
186 au = noperserv_get_autheduser(newaccount);
187 if(au) {
188 controlreply(np, "Authname already registered.");
189 return CMD_ERROR;
190 }
191
7078aa50 192 au = noperserv_new_autheduser(newaccount->userid, newaccount->name);
3e3692bf
CP
193 if(!au) {
194 controlreply(np, "Memory allocation error.");
195 return CMD_ERROR;
196 }
197
198 if(noperserv_get_autheduser_count() == 1) {
199 au->authlevel = NO_FIRST_USER_LEVEL;
200 au->noticelevel = NO_FIRST_USER_DEFAULT_NOTICELEVEL;
201 } else {
202 au->authlevel = NO_DEFAULT_LEVEL;
203 au->noticelevel = NO_DEFAULT_NOTICELEVEL;
204 }
205
3e3692bf
CP
206 noperserv_update_autheduser(au);
207
7078aa50
GB
208 for(np2=newaccount->nicks;np2;np2=np2->nextbyauthname) {
209 controlreply(np2, "An account has been created for you (auth %s).", au->authname->name);
210 if(NOGetAuthLevel(au))
211 controlreply(np2, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags));
212 controlreply(np2, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
213 }
3e3692bf 214
7078aa50
GB
215 if(np->auth==newaccount) { /* send a message to the person who HELLO'ed if we haven't already been told */
216 controlreply(np, "Account created for auth %s.", au->authname->name);
3e3692bf
CP
217 if(NOGetAuthLevel(au))
218 controlreply(np, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags));
219 controlreply(np, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
220 controlreply(np, "Instructions sent to all authed users.");
7078aa50 221 } else if(newaccount->nicks && newaccount->nicks->next) { /* if we have already been told, tell the user it was sent to more than themselves */
3e3692bf
CP
222 controlreply(np, "Instructions sent to all authed users.");
223 }
224
7078aa50 225 controlwall(NO_OPERED, NL_MANAGEMENT, "%s/%s just HELLO'ed: %s", np->nick, np->authname, au->authname->name);
3e3692bf
CP
226 return CMD_OK;
227}
228
229no_autheduser *noperserv_autheduser_from_command(nick *np, char *command, int *typefound, char **returned) {
230 no_autheduser *au;
7078aa50 231 authname *anp;
3e3692bf 232 if(command[0] == '#') {
7078aa50
GB
233 anp = findauthnamebyname(command + 1);
234 if(!anp) {
235 controlreply(np, "Authname not found.");
236 return NULL;
237 }
238 au = noperserv_get_autheduser(anp);
3e3692bf
CP
239 if(!au) {
240 controlreply(np, "Authname not found.");
241 } else {
242 *typefound = NO_FOUND_AUTHNAME;
7078aa50 243 *returned = au->authname->name;
3e3692bf
CP
244 return au;
245 }
246 } else {
247 nick *np2 = getnickbynick(command);
248 if(!np2) {
249 controlreply(np, "Nickname not on the network.");
7078aa50 250 return NULL;
3e3692bf
CP
251 }
252 if(!IsAccount(np2)) {
253 controlreply(np, "User is not authed with the network.");
7078aa50 254 return NULL;
3e3692bf
CP
255 }
256 au = NOGetAuthedUser(np2);
257 if(!au) {
258 controlreply(np, "User does not have an account.");
259 } else {
260 *typefound = NO_FOUND_NICKNAME;
261 *returned = np2->nick;
262 return au;
263 }
264 }
265
266 return NULL;
267}
268
269int noperserv_noticeflags(void *sender, int cargc, char **cargv) {
7078aa50 270 nick *np2, *np = (nick *)sender;
3e3692bf
CP
271 no_autheduser *au;
272
273 if(cargc == 1) {
274 if((cargv[0][0] == '+') || (cargv[0][0] == '-')) {
275 int ret;
276 au = NOGetAuthedUser(np);
277 flag_t fwas = NOGetNoticeLevel(au), permittedchanges = noperserv_policy_permitted_noticeflags(au);
278
279 ret = setflags(&au->noticelevel, permittedchanges, cargv[0], no_noticeflags, REJECT_DISALLOWED | REJECT_UNKNOWN);
280 if(ret != REJECT_UNKNOWN) {
281 if(ret == REJECT_DISALLOWED) {
282 flag_t fnow = fwas;
283 setflags(&fnow, NL_ALL, cargv[0], no_noticeflags, REJECT_NONE);
284 if(fnow == fwas) {
285 controlreply(np, "No changes made to existing flags.");
286 } else {
287 char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN];
288 controlreply(np, "Flag alterations denied.");
289
290 strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
291 strlcpy(ournoticeflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(ournoticeflags));
292 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, printflagdiff(fwas, fnow, no_noticeflags));
293 return CMD_ERROR;
294 }
295 } else if(ret == REJECT_NONE) {
296 if(NOGetNoticeLevel(au) == fwas) {
297 controlreply(np, "No changes made to existing flags.");
298 } else {
299 char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN], diff[FLAGBUFLEN * 2 + 1], finalflags[FLAGBUFLEN];
3e3692bf
CP
300 noperserv_update_autheduser(au);
301 controlreply(np, "Flag alterations complete.");
302
303 strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
304 strlcpy(ournoticeflags, printflags(fwas, no_noticeflags), sizeof(ournoticeflags));
305 strlcpy(diff, printflagdiff(fwas, NOGetNoticeLevel(au), no_noticeflags), sizeof(diff));
306 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, diff);
307
308 strlcpy(finalflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(finalflags));
7078aa50
GB
309 for(np2=au->authname->nicks;np2;np2=np2->nextbyauthname)
310 if(np2 != np) {
311 controlreply(np2, "!!! %s just used NOTICEFLAGS (%s): %s", np->nick, ournoticeflags, diff);
312 controlreply(np2, "Your notice flags are %s", finalflags);
3e3692bf
CP
313 }
314 }
315 }
316 } else {
317 controlreply(np, "Unknown flag(s) supplied.");
318 return CMD_ERROR;
319 }
320 } else {
321 int typefound;
322 char *itemfound;
323 au = noperserv_autheduser_from_command(np, cargv[0], &typefound, &itemfound);
324 if(!au)
325 return CMD_ERROR;
326
327 if(au != NOGetAuthedUser(np)) {
328 controlreply(np, "Notice flags for %s %s are: %s", typefound==NO_FOUND_NICKNAME?"user":"authname", itemfound, printflags(NOGetNoticeLevel(au), no_noticeflags));
329 return CMD_OK;
330 }
331 }
332 } else {
333 au = NOGetAuthedUser(np);
334 }
335
336 if(!au) /* shouldn't happen */
337 return CMD_ERROR;
338
339 controlreply(np, "Your notice flags are: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
340
341 return CMD_OK;
342}
343
344/* @test */
345int noperserv_deluser(void *sender, int cargc, char **cargv) {
7078aa50 346 nick *np2, *np = (nick *)sender;
3e3692bf
CP
347 no_autheduser *target /* target user */, *au = NOGetAuthedUser(np); /* user executing command */
348 char *userreturned = NULL; /* nickname or authname of the target, pulled from the db */
349 int typefound; /* whether it was an authname or a username */
3e3692bf
CP
350 char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], deleteduser[NOMax(ACCOUNTLEN, NICKLEN) + 1];
351
352 if(cargc != 1)
353 return CMD_USAGE;
354
355 target = noperserv_autheduser_from_command(np, cargv[0], &typefound, &userreturned);
356 if(!target)
357 return CMD_ERROR;
358
359 strlcpy(targetflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(targetflags));
360 strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
361
362 /* we have to copy it as it might point to an autheduser, which we're about to delete */
363 strlcpy(deleteduser, userreturned, sizeof(deleteduser));
364
365 /* we have to check if target != au, because if successful policy_modification_permitted just returns the flags we're allowed
366 to modify, if we have no flags we won't be able to delete ourselves */
367 if((target != au) && !noperserv_policy_permitted_modifications(au, target)) {
368 controlreply(np, "Deletion denied.");
7078aa50 369 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to DELUSER %s (%s)", np->nick, np->authname, ourflags, target->authname->name, targetflags);
3e3692bf
CP
370
371 return CMD_ERROR;
372 }
373
7078aa50
GB
374 for(np2=target->authname->nicks;np2;np2=np2->nextbyauthname)
375 if(np2 != np)
376 controlreply(np2, "!!! %s/%s (%s) just DELUSERed you.", np->nick, np->authname, ourflags);
3e3692bf
CP
377
378 noperserv_delete_autheduser(target);
379
7078aa50 380 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used DELUSER on %s (%s)", np->nick, np->authname, ourflags, deleteduser, targetflags);
3e3692bf
CP
381
382 if(target == au) {
383 controlreply(np, "You have been deleted.");
384 } else {
385 controlreply(np, "%s %s deleted.", typefound==NO_FOUND_AUTHNAME?"Auth":"User", deleteduser);
386 }
387
388 return CMD_OK;
389}
390
391/* @test */
392/* this command needs LOTS of checking */
393int noperserv_userflags(void *sender, int cargc, char **cargv) {
7078aa50 394 nick *np2, *np = (nick *)sender;
3e3692bf
CP
395 no_autheduser *au = NOGetAuthedUser(np), *target = NULL;
396 char *flags = NULL, *nicktarget = NULL;
397 int typefound;
398
399 if(cargc == 0) {
400 target = au;
401 } else if(cargc == 1) {
402 if((cargv[0][0] == '+') || (cargv[0][0] == '-')) { /* modify our own */
403 flags = cargv[0];
404 target = au;
405 } else { /* viewing someone elses */
406 nicktarget = cargv[0];
407 }
408 } else if(cargc == 2) {
409 nicktarget = cargv[0];
410 flags = cargv[1];
411 } else {
412 return CMD_USAGE;
413 }
414
415 if(nicktarget) {
416 target = noperserv_autheduser_from_command(np, nicktarget, &typefound, &nicktarget);
417 if(!target)
418 return CMD_ERROR;
419 }
420
421 if(flags) {
422 int ret;
423 flag_t permitted = noperserv_policy_permitted_modifications(au, target), fwas = NOGetAuthLevel(target), fours = NOGetAuthLevel(au);
424
425 ret = setflags(&target->authlevel, permitted, flags, no_userflags, REJECT_DISALLOWED | REJECT_UNKNOWN);
426 if(ret != REJECT_UNKNOWN) {
427 if(ret == REJECT_DISALLOWED) {
428 flag_t fnow = fwas;
429 setflags(&fnow, NO_ALL_FLAGS, flags, no_userflags, REJECT_NONE);
430 if(fnow == fwas) {
431 controlreply(np, "No changes made to existing flags.");
432 } else {
433 char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN];
434 controlreply(np, "Flag alterations denied.");
435
436 strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags));
437 strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags));
438
7078aa50 439 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to use USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->name, targetflags, printflagdiff(fwas, fnow, no_userflags));
3e3692bf
CP
440 return CMD_ERROR;
441 }
442 } else if(ret == REJECT_NONE) {
443 if(NOGetAuthLevel(target) == fwas) {
444 controlreply(np, "No changes made to existing flags.");
445 } else {
446 char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], finalflags[FLAGBUFLEN];
3e3692bf
CP
447
448 noperserv_policy_update_noticeflags(fwas, target);
449 noperserv_update_autheduser(target);
450
451 controlreply(np, "Flag alterations complete.");
452
453 strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags));
454 strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags));
455
7078aa50 456 controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->name, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags));
3e3692bf
CP
457
458 strlcpy(finalflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(finalflags));
7078aa50
GB
459 for(np2=target->authname->nicks;np2;np2=np2->nextbyauthname)
460 if(np2 != np) {
461 controlreply(np2, "!!! %s/%s (%s) just used USERFLAGS on you (%s): %s", np->nick, np->authname, ourflags, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags));
462 controlreply(np2, "Your user flags are now: %s", finalflags);
463 controlreply(np2, "Your notice flags are now: %s", printflags(target->noticelevel, no_noticeflags));
3e3692bf
CP
464 }
465 }
466 }
467 } else {
468 controlreply(np, "Unknown flag(s) supplied.");
469 return CMD_ERROR;
470 }
471 }
472
473 if(target != au) {
474 controlreply(np, "User flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(NOGetAuthLevel(target), no_userflags));
475 controlreply(np, "Notice flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(target->noticelevel, no_noticeflags));
476 } else {
477 controlreply(np, "Your user flags are: %s", printflags(NOGetAuthLevel(target), no_userflags));
478 controlreply(np, "Your notice flags are: %s", printflags(target->noticelevel, no_noticeflags));
479 }
480
481 return CMD_OK;
482}
483
484void noperserv_oper_detection(int hooknum, void *arg) {
510b754a 485 nick *np = (nick *)arg;
3e3692bf 486
3e3692bf 487 if(np->umodes & UMODE_OPER) {
510b754a
CP
488 if(np->opername && strcmp(np->opername->content, "-")) {
489 controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just OPERed as %s", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"", np->opername->content);
490 } else {
3e3692bf 491 controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just OPERed", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"");
510b754a
CP
492 }
493 } else {
494 controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just DEOPERed", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"");
3e3692bf
CP
495 }
496}