8
+ − 1
<?php
+ − 2
+ − 3
// most of the code in here goes towards keeping track of the list of members currently in the various channels we're in.
+ − 4
+ − 5
$stats_memberlist = array();
+ − 6
$stats_prefixes = array(
+ − 7
'o' => '@',
+ − 8
'v' => '+'
+ − 9
);
+ − 10
$stats_data = array('anonymous' => array(), 'messages' => array());
+ − 11
@include('./stats-data.php');
+ − 12
unset($stats_data['members']);
+ − 13
$stats_data['members'] =& $stats_memberlist;
+ − 14
+ − 15
eb_hook('event_self_join', 'stats_init_channel($this);');
+ − 16
eb_hook('event_raw_message', 'stats_process_message($chan, $message);');
+ − 17
eb_hook('snippet_dynamic', 'if ( $snippet === "memberlist" ) return stats_list_members($chan, $message); if ( $snippet === "deluser" ) return stats_del_user($chan, $message);');
+ − 18
eb_hook('event_other', 'stats_handle_other_event($message);');
+ − 19
eb_hook('event_privmsg', 'stats_handle_privmsg($message);');
+ − 20
+ − 21
function stats_init_channel(&$chan)
+ − 22
{
+ − 23
global $stats_memberlist, $stats_prefixes, $stats_data;
+ − 24
+ − 25
$channel_name = $chan->get_channel_name();
+ − 26
$stats_memberlist[$channel_name] = array();
+ − 27
$prefixes_regexp = '/^([' . preg_quote(implode('', $stats_prefixes)) . '])+/';
+ − 28
$prefixes_flipped = array_flip($stats_prefixes);
+ − 29
$prefixes_regexp_notlist = '/[^' . preg_quote(implode('', $prefixes_flipped)) . ']/';
+ − 30
+ − 31
if ( !isset($stats_data['messages'][$channel_name]) )
+ − 32
{
+ − 33
$stats_data['messages'][$channel_name] = array();
+ − 34
}
+ − 35
+ − 36
// read list of members from channel
+ − 37
@stream_set_timeout($chan->parent->sock, 3);
+ − 38
while ( $msg = $chan->parent->get() )
+ − 39
{
+ − 40
if ( $ml = strstr($msg, ' 353 ') )
+ − 41
{
+ − 42
$memberlist = trim(substr(strstr($ml, ':'), 1));
+ − 43
$stats_memberlist[$channel_name] = explode(' ', $memberlist);
+ − 44
$stats_memberlist[$channel_name] = array_flip($stats_memberlist[$channel_name]);
+ − 45
foreach ( $stats_memberlist[$channel_name] as $nick => $_ )
+ − 46
{
+ − 47
$stats_memberlist[$channel_name][$nick] = '';
+ − 48
while ( preg_match($prefixes_regexp, $nick) )
+ − 49
{
+ − 50
$prefix = substr($nick, 0, 1);
+ − 51
$add = preg_replace($prefixes_regexp_notlist, '', strval($stats_memberlist[$channel_name][$nick]));
+ − 52
unset($stats_memberlist[$channel_name][$nick]);
+ − 53
$nick = substr($nick, 1);
+ − 54
$stats_memberlist[$channel_name][$nick] = $prefixes_flipped[$prefix] . $add;
+ − 55
}
+ − 56
}
+ − 57
break;
+ − 58
}
+ − 59
}
+ − 60
}
+ − 61
+ − 62
function stats_process_message(&$chan, $message)
+ − 63
{
+ − 64
global $stats_memberlist, $stats_data;
+ − 65
$channel_name = $chan->get_channel_name();
+ − 66
if ( !isset($stats_memberlist[$channel_name]) )
+ − 67
{
+ − 68
return false;
+ − 69
}
+ − 70
+ − 71
$ml =& $stats_memberlist[$channel_name];
+ − 72
+ − 73
// we need to change statistics accordingly depending on the event
+ − 74
if ( $message['action'] == 'JOIN' )
+ − 75
{
+ − 76
// member joined - init their flags and up the member count by one
+ − 77
$ml[$message['nick']] = '';
+ − 78
}
+ − 79
else if ( $message['action'] == 'PART' )
+ − 80
{
+ − 81
// member left - clear flags and decrement the total member count
+ − 82
unset($ml[$message['nick']]);
+ − 83
$ml = array_values($ml);
+ − 84
}
+ − 85
else if ( $message['action'] == 'MODE' )
+ − 86
{
+ − 87
// update member list (not sure why this would be useful, but export it anyway - display scripts might find it useful)
+ − 88
list($mode, $target) = explode(' ', $message['message']);
+ − 89
$action = substr($mode, 0, 1);
+ − 90
+ − 91
global $stats_prefixes;
+ − 92
$ml[$target] = str_replace(substr($mode, 1), '', $ml[$target]);
+ − 93
if ( $action == '+' )
+ − 94
{
+ − 95
$ml[$target] .= substr($mode, 1);
+ − 96
}
+ − 97
}
+ − 98
else if ( $message['action'] == 'PRIVMSG' )
+ − 99
{
+ − 100
// private message into $channel_name - mark the user active and log the message time
+ − 101
if ( isset($stats_data['anonymous'][$message['nick']]) )
+ − 102
$message['nick'] = 'Anonymous';
+ − 103
+ − 104
$messages =& $stats_data['messages'][$channel_name];
+ − 105
+ − 106
$messages[] = array(
+ − 107
'time' => time(),
+ − 108
'nick' => $message['nick']
+ − 109
);
+ − 110
}
+ − 111
+ − 112
stats_cron();
+ − 113
}
+ − 114
+ − 115
function stats_list_members(&$chan, &$message)
+ − 116
{
+ − 117
global $stats_memberlist;
+ − 118
$channel_name = $chan->get_channel_name();
+ − 119
if ( !isset($stats_memberlist[$channel_name]) )
+ − 120
{
+ − 121
return false;
+ − 122
}
+ − 123
+ − 124
$ml =& $stats_memberlist[$channel_name];
+ − 125
+ − 126
$chan->parent->privmsg($message['nick'], "memberlist:\n" . str_replace("\n", ' ', print_r($ml, true)));
+ − 127
+ − 128
return true;
+ − 129
}
+ − 130
+ − 131
function stats_del_user(&$chan, &$message)
+ − 132
{
+ − 133
global $stats_memberlist, $privileged_list, $irc, $stats_data;
+ − 134
+ − 135
// remove a user from the DB
+ − 136
$targetuser = trim(substr(strstr($message['message'], '|'), 1));
+ − 137
if ( empty($targetuser) )
+ − 138
$targetuser = $message['nick'];
+ − 139
+ − 140
if ( $targetuser != $message['nick'] && !in_array($message['nick'], $privileged_list) )
+ − 141
{
+ − 142
$irc->privmsg($message['nick'], "Sorry, you need to be a moderator to delete statistics for users other than yourself.");
+ − 143
return true;
+ − 144
}
+ − 145
+ − 146
// we should be good - delete the user
+ − 147
foreach ( $stats_data['messages'] as $channel => &$messages )
+ − 148
{
+ − 149
foreach ( $messages as $i => &$currentmessage )
+ − 150
{
+ − 151
if ( $currentmessage['nick'] == $targetuser )
+ − 152
{
+ − 153
unset($messages[$i]);
+ − 154
}
+ − 155
}
+ − 156
$messages = array_values($messages);
+ − 157
}
+ − 158
unset($users, $currentmessage, $messages);
+ − 159
+ − 160
global $nick;
+ − 161
$greeting = ( $targetuser == $message['nick'] ) ? "All of your statistics data" : "All of {$targetuser}'s statistic data";
+ − 162
$irc->privmsg($message['nick'], "$greeting has been removed from the database for all channels. The changes will show up in the next commit to disk, which is usually no more than once every two minutes.");
+ − 163
$irc->privmsg($message['nick'], "Want your stats to be anonymized in the future? Type /msg $nick anonymize to make me keep all your stats anonymous in the future. This only applies to your current nick though - for example if you change your nick to \"{$message['nick']}|sleep\" or similar your information will not be anonymous.");
+ − 164
$irc->privmsg($message['nick'], "You can't clear your logs if you're anonymous. Type /msg $nick denonymize to remove yourself from the anonymization list. Anonymized logs can't be converted back to their original nicks.");
+ − 165
+ − 166
return true;
+ − 167
}
+ − 168
+ − 169
function stats_handle_privmsg(&$message)
+ − 170
{
+ − 171
global $irc, $stats_data, $nick;
+ − 172
static $poll_list = array();
+ − 173
+ − 174
$message['message'] = strtolower($message['message']);
+ − 175
+ − 176
if ( trim($message['message']) === 'anonymize' )
+ − 177
{
+ − 178
$stats_data['anonymous'][$message['nick']] = true;
+ − 179
$poll_list[$message['nick']] = true;
+ − 180
$irc->privmsg($message['nick'], "Anonymization complete. Any further statistics recorded about you will be anonymous.");
+ − 181
$irc->privmsg($message['nick'], "Do you want to also anonymize any past statistics about you? (type \"yes\" or \"no\")");
+ − 182
}
+ − 183
else if ( trim($message['message']) === 'denonymize' )
+ − 184
{
+ − 185
$stats_data['anonymous'][$message['nick']] = false;
+ − 186
unset($stats_data['anonymous'][$message['nick']]);
+ − 187
$irc->privmsg($message['nick'], "Denonymization complete. Any further statistics recorded about you will bear your nick. Remember that you can always change this with /msg $nick anonymize.");
+ − 188
}
+ − 189
else if ( trim($message['message']) === 'yes' && isset($poll_list[$message['nick']]) )
+ − 190
{
+ − 191
// anonymize logs for this user
+ − 192
// we should be good - delete the user
+ − 193
$targetuser = $message['nick'];
+ − 194
+ − 195
foreach ( $stats_data['messages'] as $channel => &$messages )
+ − 196
{
+ − 197
foreach ( $messages as $i => &$currentmessage )
+ − 198
{
+ − 199
if ( $currentmessage['nick'] == $targetuser )
+ − 200
{
+ − 201
$currentmessage['nick'] = 'Anonymous';
+ − 202
}
+ − 203
}
+ − 204
$messages = array_values($messages);
+ − 205
}
+ − 206
unset($users, $currentmessage, $messages);
+ − 207
$irc->privmsg($message['nick'], "Anonymization complete. All past statistics on your nick are now anonymous.");
+ − 208
+ − 209
unset($poll_list[$message['nick']]);
+ − 210
}
+ − 211
stats_cron();
+ − 212
}
+ − 213
+ − 214
function stats_handle_other_event(&$message)
+ − 215
{
+ − 216
global $stats_memberlist;
+ − 217
+ − 218
if ( $message['action'] == 'NICK' )
+ − 219
{
+ − 220
// we have a nick change; go through all channels and replace the old nick with the new
+ − 221
foreach ( $stats_memberlist as &$ml )
+ − 222
{
+ − 223
if ( isset($ml[$message['nick']]) )
+ − 224
{
+ − 225
$ml[$message['message']] = $ml[$message['nick']];
+ − 226
unset($ml[$message['nick']]);
+ − 227
}
+ − 228
}
+ − 229
}
+ − 230
stats_cron();
+ − 231
}
+ − 232
+ − 233
function stats_cron()
+ − 234
{
+ − 235
static $commit_time = 0;
+ − 236
$now = time();
+ − 237
// commit to disk every 1 minute
+ − 238
if ( $commit_time + 60 < $now )
+ − 239
{
+ − 240
$commit_time = $now;
+ − 241
stats_commit();
+ − 242
}
+ − 243
}
+ − 244
+ − 245
function stats_commit()
+ − 246
{
+ − 247
global $stats_data;
+ − 248
ob_start();
+ − 249
var_export($stats_data);
+ − 250
$stats_data_exported = ob_get_contents();
+ − 251
ob_end_clean();
+ − 252
+ − 253
$fp = @fopen('./stats-data.php', 'w');
+ − 254
if ( !$fp )
+ − 255
return false;
+ − 256
fwrite($fp, "<?php\n\$stats_data = $stats_data_exported;\n");
+ − 257
fclose($fp);
+ − 258
}
+ − 259