PDA

View Full Version : Miscellaneous Hacks - IRC Eggdrop Bot <---> vBulletin site


Sarteck
07-31-2012, 10:00 PM
A user here recently asked me about my "Users on IRC" modification. It's actually part of a fairly elaborate system of communication between my Eggdrop bots and my vBulletin site.

If you would like communication between your IRC Channel and your vBulletin site, read on.

I'm going to assume that you have an Eggdrop bot running already. If you don't, then none of this will work. I will not cover the installation and configuration of Eggdrop bots here. You can find plenty of articles online to help you there.

Also, I use the Rizon network, though I believe that most networks with NickServ services will work fine.





Okay, first thing you have to do is create some Options in your vBulletin Settings. (To do this, you have to be in Debug Mode.)

We need to create two Options. It doesn't matter if you make a separate group for them or not, and it doesn't matter what the human-readable names for them are--they will only be used for storing and retrieving info. The variable names, however, need to be: ircactivity and irclastcheck.



Next thing we need to do is create a new User Profile Field that your users can edit. This Profile Field is where the users will put their IRC handle(s). If they have more than one handle, they an separate them by commas (no spaces before or after!!!). Take note of the field name created--we'll need to remember it for the PHP Script.



Now, we come to the PHP Script. Take note of the first 15 lines--this will contain the stuff that you need to modify.

<?php
error_reporting(E_ALL & ~E_NOTICE);
define('THIS_SCRIPT', 'irc'); /// Modify this to be whatever you want to name your IRC Script.
define('IRC_HANDLE_FIELD', 'field123'); /// Modify this to whatever Profile Field on your forum you have for IRC Handles
require_once('./global.php');


$allowed_ip_addresses = array();
/// We will allow connections from the webserver
$allowed_ip_addresses[] = '127.0.0.1'; // Modify if necessary.
/// We will allow connections from the server the IRC Bot is running on.
$allowed_ip_addresses[] = '1.2.3.4'; // Modify or comment out if the IRC Bot is running on the same server.
/// You can allow other IP Addresses for testing purposes in this manner as well.

if (!in_array($_SERVER['REMOTE_ADDR'],$allowed_ip_addresses)) {print_no_permission(); die();}








/// Retrieves Userinfo given a specific IRC Handle
function get_user_by_irc_handle($handle)
{
global $vbulletin;
$result = $vbulletin->db->query_read(sprintf("SELECT userid FROM ".TABLE_PREFIX."userfield WHERE FIND_IN_SET('%s',%s)", $vbulletin->db->escape_string($handle),IRC_HANDLE_FIELD));
if (!$result) {return false;}
if ($vbulletin->db->num_rows($result) < 1) {return false;}
if ($vbulletin->db->num_rows($result) > 1) {return 2;}
$uid = 0;
while ($info = $vbulletin->db->fetch_array($result)) {$uid = $info['userid'];}
$user = fetch_userinfo($uid);
return $user;
}

/// Retrieves Userinfo given a Username
function get_user_by_vb_name($name)
{
global $vbulletin;
$result = $vbulletin->db->query_read(sprintf("SELECT userid FROM ".TABLE_PREFIX."user WHERE username='%s'", $vbulletin->db->escape_string($name)));
if (!$result) {return false;}
if ($vbulletin->db->num_rows($result) < 1) {return false;}
if ($vbulletin->db->num_rows($result) > 1) {return 2;}
$uid = 0;
while ($info = $vbulletin->db->fetch_array($result)) {$uid = $info['userid'];}
$user = fetch_userinfo($uid);
return $user;
}











/// This will be called by the IRC Bot every minute.
/// It checks for active users on the channel, and sets the info to the setting table
if ($_REQUEST['do'] == 'irc_activity_check')
{
$ircnames = $vbulletin->input->clean_gpc('r', 'users', TYPE_STR);
$users = array();
foreach (explode(' ',$ircnames) AS $handle)
{
$search = array('{[',']}','\\\\');
$replace = array('[', ']','\\');
$handl_parsed = str_replace($search, $replace, $handle);
$user = get_user_by_irc_handle($handl_parsed);
if ($user)
{
$user['irchandle'] = $handl_parsed;
$users[$user['userid']] = $user;
}
else {$user['musername'] = $handl_parsed; $users[] = $user;}
}
$irc_users = array();
foreach ($users AS $userid => $user) {if ($user['userid']) {$irc_users[] = '<a href="member.php?u='.$user['userid'].'">'.$user['musername'].'</a>';} else {$irc_users[] = $user['musername'];}}
$query = sprintf("UPDATE setting SET value='%d' WHERE varname='irclastcheck'", TIMENOW);
$vbulletin->db->query_write($query);
$query = sprintf("UPDATE setting SET value='%s' WHERE varname='ircactivity'",$vbulletin->db->escape_string(implode(', ',$irc_users)));
$vbulletin->db->query_write($query);
die($query);
}

/// This is for when Users do a "!whois" command on the IRC Channel
if ($_POST['do'] == 'whois')
{
$whois = $vbulletin->input->clean_gpc('p', 'whois', TYPE_STR);
$user = get_user_by_irc_handle($whois);
if (!$user) {die('The IRC Nickname you specified, '.$whois.', does not exist in the Club Bleach Database.');}
if ($user == 2) {die('The IRC Nickname you specified, '.$whois.', is taken by more than one account in the Club Bleach Database. Contact an Admin to get to the bottom of things.');}
die($whois.' has the Club Bleach Username of: '.$user['username']);
}

/// This is for when Users do a "!rwhois" command on the IRC Channel
if ($_POST['do'] == 'rwhois')
{
$whois = $vbulletin->input->clean_gpc('p', 'whois', TYPE_STR);
$user = get_user_by_vb_name($whois);
if (!$user) {die('The IRC Nickname you specified, '.$whois.', is not registered at Club Bleach.');}
$names = explode(',',$user[IRC_HANDLE_FIELD]);
if (sizeof($names) > 1) {die($whois.' has the IRC Nicknames of: '.$user[IRC_HANDLE_FIELD]);}
die($whois.' has the IRC Nickname of: '.$user[IRC_HANDLE_FIELD]);
}

/// If we get this far, something went wrong.
die($_SERVER['QUERY_STRING'] . ' -- ' . $_REQUEST['do'] . ' --: ERGH');




?>
(This is a VERY trimmed-down version of what I've got, but the stuff I omitted is largely specific to my particular forum, it's "item" database, it's Triple Triad cards, etc. This includes the check for IRC activity for the stuff in WGO, as well as simple WHOIS and REVERSE WHOIS functions to see who a IRC user is on the forum, or to see what a Forum User's IRC Handle is.)




And now, the Tcl script that you'd use for your Eggdrop bot. Again, pay particular attention to the first 15 lines--the Comments tell you what you'll have to Modify.
### vb.tcl
###
### Our vb.tcl script does the following:
### -- auto - Keeps an array of IRC Nickname => status. Status of '3' is 'IDENTIFIED.'
### -- auto - Sets nickstatus list every other minute to a file for Woogy to read
### -- !whois checks an IRC handle to see what CB Username it belongs to
### -- !rwhois checks a vBulletin Username to see what IRC handle it has (can be multiple names)
### -- FUNCTION: isIdentified - returns true if a nick is ID'd with the Bot, false otherwise.
###
### NOTE: Find and replace the following:
### -- http://link.to.your.forum/irc.script.php
### -- #YourChannel
### NOTE: If you have Bots on your channel (including the Bot running this!), change the
### isBot procedure below.
putlog "% Loading Nickname functions"




################################################## #############################
### Binds (these call the procedures) ###
################################################## #############################


bind pub - !whois doWhois
bind pub - !rwhois doRWhois

bind notc - "*STATUS*" doSetStatus
bind time - "* * * * *" doSendNames
bind time - "* * * * *" doGetNames
bind time - "* * * * *" doSetNames

################################################## #############################
### Procedures called by public bind events ###
################################################## #############################




proc doWhois {nick host hand chan text} {
package require http
set url http://link.to.your.forum/irc.script.php
set querystring [http::formatQuery "do" "whois" "whois" $text]
set token [http::geturl $url -query $querystring]
set data [http::data $token]
http::cleanup $token
putquick "PRIVMSG #YourChannel :$data"
putloglev p $chan "$data"
return $data
}

proc doRWhois {nick host hand chan text} {
package require http
set url http://link.to.your.forum/irc.script.php
set querystring [http::formatQuery "do" "rwhois" "whois" $text]
set token [http::geturl $url -query $querystring]
set data [http::data $token]
http::cleanup $token
putquick "PRIVMSG #YourChannel :$data"
putloglev p $chan "$data"
return $data
}


### bind time - "0/2/4/6/8 * * * *" doSendNames
### -- (once per two minutes)
### saves nickstatus to nickstatus.txt once every other minute (even minutes)
proc doSendNames {min hour day month year} {
global nickstatus
set out [open "nickstatus.txt" w]
puts $out [array get nickstatus]
close $out
global nicktime
set out [open "nicktime.txt" w]
puts $out [array get nicktime]
close $out
}



### bind time - "* * * * *" doSetNames
### -- (once per minute)
### Check each name in the status and time lists
### If the STATUS is 3, add the name to the list send to the database
### If the user has not been checked for 30 minutes, unset them from the arrays
### Set namelist to server (displays in "Who's Online")
proc doSetNames {min hour day month year} {
global nickstatus
global nicktime
set identifiedUsers ""
foreach userraw [chanlist "#YourChannel"] {
set username [doGetSafe $userraw]
if {[info exists nickstatus($username)]} {
if {$nickstatus($username) == 3} {
lappend identifiedUsers $username
}
if {$nicktime($username) < [clock seconds] - 1800} {
unset nickstatus($username)
unset nicktime($username)
}
}
}
set NamesSet [setVBNames $identifiedUsers]
putlog "doSetNames: Users -- $identifiedUsers"
}

proc doGetSafe {mystring} {
return $mystring
}


### Get Names on channel, send Status request to NickServ for each name on nicklist without STATUS of 3, once per minute
### bind time - "* * * * *" doGetNames
### -- (once per minute)
### If: NICK IS NOT A BOT
### -- nick does not exist, OR
### -- nick is not level 3 OR
### -- nicktime last checked is over 10 minutes
### THEN -- send a STATUS request to NickServ.
### All nicks (except bots)
proc doGetNames {min hour day month year} {
global nickstatus
global nicktime
foreach userraw [chanlist "#YourChannel"] {
set username [doGetSafe $userraw]
set NickIsBot [isBot $username]
set NickExists [info exists nickstatus($username)]
set NowTime [clock seconds]
if {$NickExists} {
set NickNotIdentified [expr ($nickstatus($username) != 3)]
set NickLastTime $nicktime($username)
} else {
set NickNotIdentified 1
set NickLastTime 0
}
set NickTimesOut [expr $NickLastTime + 600 - $NowTime]
set NickTimedOut [expr $NickTimesOut < 0]
##putlog " --- STATUS Checking :$username -- $NickIsBot - $NickExists - $NickNotIdentified - $NickTimedOut"
if {!$NickIsBot} {
if {(!$NickExists || $NickNotIdentified || $NickTimedOut)} {
puthelp "PRIVMSG NickServ :STATUS $username"
putlog "doGetNames: Checking $username"
}
}
}
}


### bind notc - "*STATUS*" doSetStatus
### Answers NickServ's status response notice, setting nickstatus and nicktime appropriately.
proc doSetStatus {nick host handle text dest} {
global nickstatus
global nicktime
if {[string tolower $nick] != [string tolower "NickServ"]} {
return 0;
}
regexp {STATUS ([^ ]*) ([0-3])} $text hmm NS_name NS_status
set nickstatus($NS_name) $NS_status
set nicktime($NS_name) [clock seconds]
putlog "doSetStatus: User -- $NS_name"
}


################################################## #############################
### Helper Functions (not called by bind events) ###
################################################## #############################

### If a user is in the global nickstatus as Identified, return true, else return false
proc isIdentified {nick} {
global nickstatus
if {[info exists nickstatus($nick)]} {
if {$nickstatus($nick) == 3} {
return 1
}
}
return 0
}

### Returns true if nick is a Bot's nickname, else false
proc isBot {nick} {
if {[string tolower $nick] == [string tolower "Bot1"]} {
return 1
}
if {[string tolower $nick] == [string tolower "Bot2"]} {
return 1
}
if {[string tolower $nick] == [string tolower "Internets"]} {
return 1
}
if {[string tolower $nick] == [string tolower "Quotes"]} {
return 1
}
if {[string tolower $nick] == [string tolower "Stats"]} {
return 1
}
return 0
}

### Sends the IRC Active users list to our page
proc setVBNames {iduserlist} {
package require http
set url http://link.to.your.forum/irc.script.php
set querystring [http::formatQuery "do" "irc_activity_check" "users" $iduserlist]
set token [http::geturl $url -query $querystring]
set data [http::data $token]
http::cleanup $token
return $data
}






After setting all this up correctly, we'll use a little plugin on the hook process_templates_complete:
$ircusers = $vbulletin->db->query_first("SELECT value FROM ".TABLE_PREFIX."setting WHERE varname='ircactivity'");
$irctime = $vbulletin->db->query_first("SELECT value FROM ".TABLE_PREFIX."setting WHERE varname='irclastcheck'");

$irctime = vbdate($vbulletin->options['dateformat'], $irctime['value'], 0)
. '--' . vbdate($vbulletin->options['timeformat'], $irctime['value'], 0);

$template_hook['forumhome_wgo_pos2'] .= '
<div style="margin:20px;margin-top:6px;margin-bottom:10px;border:3px outset #556655;padding:3px;">
<h3>Users on IRC as of '.$irctime.'</h3>
<div>'.$ircusers['value'].'</div>
</div>';



This will activate a IRC Users in WGO that looks like this:
https://vborg.vbsupport.ru/external/2012/08/132.png





You can add additional functions to your Eggdrop--have people PM from IRC to users on your vBulletin, have a function that reports statistics to IRC, etc. Just follow the examples of the !whois and !rwhois functions.

You can even return multi-line data. Take the example procedure below:

proc example {nick host hand chan text} {
package require http
set url http://link.to.your.site/irc.script.php
set querystring [http::formatQuery "do" "example"]
set token [http::geturl $url -query $querystring]
set data [http::data $token]
foreach $splitline [split $data "\n"] {
putquick "PRIVMSG #YourChannel :$splitline"
}
http::cleanup $token
}
This will print out one line in IRC for each line the page has of content. Great for, say, outputting the members of a usergroup or something similar.





This code is not meant to use "as is," but is rather meant to be a reference for vB owners to be able to interface with their IRC channels. Or at least to give them a shove in the right direction. It will work (as long as you make the noted modifications) to place a IRC User List in "WGO", so I guess I can put it here in the Modifications. X3



Questions, comments? Post them.

M.Iftikhar
08-01-2012, 02:14 PM
where is live demo link.......??????????????????

Sarteck
08-01-2012, 02:19 PM
You can view it at my forum, I guess. http://www.cleverbaka.com . But I think the screenshot is more or less good enough. XP

Skyrider
08-02-2012, 06:28 AM
Perhaps a nifty little button to join the IRC channel where the users are being displayed? :)

Sarteck
08-02-2012, 09:21 AM
For such a thing, you'd need only add the Button/Link code you want to the plugin where data is added to $template_hook['forumhome_wgo_pos2']. :3

AlexanderT
08-09-2012, 01:56 PM
You can view it at my forum, I guess. http://www.cleverbaka.com . But I think the screenshot is more or less good enough. XP

That's quite intriguing. Congrats!

Question, I am in the process of setting up IRC, and so far I've only configured the IRC daemon (I picked charybdis). I also have atheme installed, but someone told me it'd be an overkill and Eggdrop would be sufficient for my needs (such as keeping a channel under control, auto +v, etc.). Would you agree?

thenashy
11-20-2012, 07:24 AM
Does this stop any non forum users joining?

Also, what do I do to just have it not show users online, I'm not interested in displaying that.

Cheers