2 * - fix STOP error when we can't find control's nick
3 * - deal with Q/fishbot/O/T clones
4 * - deal with our own localusers
9 #include "../lib/version.h"
10 #include "../lib/ccassert.h"
11 #include "../lib/strlfunc.h"
12 #include "../core/error.h"
13 #include "../core/hooks.h"
14 #include "../core/schedule.h"
15 #include "../irc/irc.h"
16 #include "../nick/nick.h"
17 #include "../control/control.h"
18 #include "signontracker.h"
20 #define MAXWHOISLINES 50 /* from the ircd */
24 static void hook_newnick(int hook
, void *arg
);
25 static void hook_rename(int hook
, void *arg
);
26 static void queue_scan_nick(nick
*np
);
27 static void flush_queue_sched(void *arg
);
28 static int whois_reply_handler(void *source
, int cargc
, char **cargv
);
29 static int cmd_listnosignonusers(void *source
, int cargc
, char **cargv
);
31 static int nickext
= -1;
33 #define QUEUEBUFLEN (MAXWHOISLINES*(NICKLEN+1)+1)
36 char buf
[QUEUEBUFLEN
];
45 CCASSERT(sizeof(time_t) <= sizeof(long));
47 nickext
= registernickext("signontracker");
51 registerhook(HOOK_NICK_NEWNICK
, &hook_newnick
);
52 registerhook(HOOK_NICK_RENAME
, &hook_rename
);
53 registernumerichandler(317, whois_reply_handler
, 7);
55 for(i
=0;i
<NICKHASHSIZE
;i
++)
56 for(np
=nicktable
[i
];np
;np
=np
->next
)
59 registercontrolhelpcmd("listnosignonusers", NO_DEVELOPER
, 0, cmd_listnosignonusers
, "Shows users without a signed on timestamp.");
68 deregistercontrolcmd("listnosignonusers", cmd_listnosignonusers
);
70 deregisterhook(HOOK_NICK_NEWNICK
, &hook_newnick
);
71 deregisterhook(HOOK_NICK_RENAME
, &hook_rename
);
72 deregisternumerichandler(317, whois_reply_handler
);
74 for(i
=0;i
<MAXSERVERS
;i
++)
75 deleteschedule(queue
[i
].sched
, flush_queue_sched
, (void *)(long)i
);
77 releasenickext(nickext
);
80 static int whois_reply_handler(void *source
, int cargc
, char **cargv
) {
87 np
= getnickbynick(cargv
[3]);
91 connected
= strtoul(cargv
[5], NULL
, 10);
92 np
->exts
[nickext
] = (void *)connected
;
94 triggerhook(HOOK_SIGNONTRACKER_HAVETIME
, np
);
99 static void flush_queue(int server
) {
100 char control_numeric
[6];
102 if(!queue
[server
].len
)
107 Error("signontracker", ERR_STOP
, "Unable to get control nick.");
110 longtonumeric2(mynick
->numeric
, 5, control_numeric
);
112 irc_send("%s W %s %s", control_numeric
, longtonumeric(server
, 2), queue
[server
].buf
);
113 queue
[server
].len
= 0;
114 queue
[server
].buf
[0] = '\0';
117 static void queue_scan_nick(nick
*np
) {
120 if(NickOnServiceServer(np
)) /* TODO: fix */
123 server
= homeserver(np
->numeric
);
125 if(queue
[server
].len
++)
126 strlcat(queue
[server
].buf
, ",", QUEUEBUFLEN
);
128 strlcat(queue
[server
].buf
, np
->nick
, QUEUEBUFLEN
);
130 if(queue
[server
].len
== MAXWHOISLINES
|| strlen(queue
[server
].buf
) > 480) {
132 } else if(queue
[server
].sched
== NULL
) {
133 queue
[server
].sched
= scheduleoneshot(time(NULL
), flush_queue_sched
, (void *)(long)server
);
137 static void flush_queue_sched(void *arg
) {
138 int server
= (long)arg
;
141 queue
[server
].sched
= NULL
;
144 static void hook_newnick(int hook
, void *arg
) {
145 nick
*np
= (nick
*)arg
;
150 static void hook_rename(int hook
, void *arg
) {
151 void **harg
= (void **)arg
;
152 nick
*np
= (nick
*)harg
[0];
154 if(getnicksignon(np
))
160 time_t getnicksignon(nick
*np
) {
164 return (time_t)np
->exts
[nickext
];
167 static int cmd_listnosignonusers(void *source
, int cargc
, char **cargv
) {
168 nick
*sender
=(nick
*)source
;
169 int i
, found
= 0, displayed
= 0;
172 for(i
=0;i
<NICKHASHSIZE
;i
++) {
173 for(np
=nicktable
[i
];np
;np
=np
->next
) {
174 if(!NickOnServiceServer(np
) && !getnicksignon(np
)) {
176 controlreply(sender
, "%s%s", np
->nick
, NickOnServiceServer(np
) ? "(S)" : " ");
183 controlreply(sender
, "Done, %d entries (%d displayed).", found
, displayed
);