
//
// Verlihub Python Plugin v.1.1
//
// Created in 2007 by Frog, frg@otaku-anime.net
// Code template based on Lua plugin, (c) 2004 by Janos Horvath, bourne@freemail.hu
// Code licensed under the GNU Library General Public License
//


Python Plugin for Verlihub brings you the ability to run python scripts in your hub.
I have written it because personally i like python very much and i know it is
a much more powerful scripting language than lua. 
However, the task of embedding it was quite a challenge.
Unlike all other plugins this one consists of not 1 but 2 shared libraries
  A)  the plugin libpython_pi.so not using any python files
  B)  the libvh_python_wrapper.so linked against libpython2.5.so
This way A can load B explicitly telling the dynamic loader to export all symbols 
from any other library B is linked with, in this case: the python library,
allowing the scripts to load any python modules existing in the system.


----------------------------------------------------------------------------------------
        Installation
----------------------------------------------------------------------------------------

Plugin requires Python version 2.5 or 2.4 to be installed on your system.
It has to be the development version with all include files.
Such package might be called python-dev in your distribution

Installation steps:

  0)  optional: check if config.sub and config.guess links point to your automake folder
  1)  optional: autoreconf
  2)  console:  configure --disable-verlihubtest
  3)  console:  make
  4)  console:  make install    (as root)
  5)  hub:      !addplug -p /usr/local/lib/libpython_pi.so -d 'Python plugin' -a 1
  6)  console:  copy the scripts from /examples/ folder into your verlihub's /scripts/ folder
  7)  hub:      !replug python

The plugin exists in your system as 2 libraries: libpython_pi.so* and libvh_python_wrapper.so*
Make sure the second one and its symlinks are in a visible place, usually: /usr/local/lib/

If you wish to stop python plugin from loading automatically write: !modplug python -a 0


----------------------------------------------------------------------------------------
        Usage
----------------------------------------------------------------------------------------

!pylog <n>    where n is 0, 1, 2, 3, 4, 5 or 6
	changes the amount of debug info the plugin sends to the console
	At first there's lots of it (n=5). If all runs fine you can change it to 1:
	!pylog 1

!pylist
	prints a list of running scripts
	what you see are: script ID number in brackets and path to the script file

!pyload <path>
	loads a script existing on the system under that path
	example: !pyload /etc/verlihub/scripts/python1.py
	
!pyunload <path>    or    !pyunload <id>
	unloads a script
	you can do that by specifying path to the file or simpler: by using script's ID

!pyreload <path>    or    !pyunload <id>
	reloads a script (unloads and then loads)
	you can do that by specifying path to the file or simpler: by using script's ID


----------------------------------------------------------------------------------------
        Example scripts
----------------------------------------------------------------------------------------

To explain how to write python scripts for verlihub and to show their capabilities
several example scripts have been included in the /examples/folder:

1)  python1.py

The general purpose script, designed for every day use - you might want to keep it.
Includes several commands that might be proven useful, some of them known from other hubs:
!sr / !say / !mc / !ui / !ck / !block / !unblock / ...
For a complete list write: !help

2)  mean.py

A funny script providing you with the silly extra functionality YnHub offered.
Allows you to kennylize, lunarize and reverse the chat messages of certain users.
Changes are stored by nick in mysql and are effective after the user reconnects.
For available commands write: !help mean

3)  callbacks.py

Test use only. Prints all callbacks and their arguments to the console.
!cblog 1    turns it on    !cblog 0    turns it off

4)  myinfo.py

A demonstrative script showing a powerful feature available in the python plugin.
You can use scripts to modify user's myinfo. In real hubs you would use that
to implement hideshare or to add important information to people's descriptions

!myinfo <flags>    specifies which part of myinfo should be modified
<flags> is a number made by adding the numbers of fields you want modified:
1=description, 2=tag, 4=speed, 8=email, 16=sharesize
so to turn everything on write: !myinfo 31    and to disable changes: !myinfo 0


----------------------------------------------------------------
        Available hooks
----------------------------------------------------------------

Hooks are functions in your script with special names that get called from the hub to handle events

the tag [blockable] means that you can block further parsing of the event by the hub 
and by other plugins (but not other python scripts)
	to block use:	return 1    or    return n    (n being an integer but not 0)
	otherwise use:	return 0    or    return
Blocking for messages means that the message won't get sent
For validating nick, myinfo or tag blocking them would make the user fail the checks and get disconnected

the tag [special] means that this hook accepts special return values


OnNewConn (ip)
	first stage of connection process
	
OnCloseConn (ip)
	connection has been terminated
	
OnUserLogin (nick)
	user successfully logged in - hook used by greeting scripts and many others
	
OnUserLogout (nick)
	used by the same scripts as the function above 
	
OnValidateTag (nick, data)				[blockable]
	called for users that undergo tag verification (check tag_min_class_ignore setting)
	
OnOperatorCommand (nick, data)				[blockable]
	commands written by operators that start with ! (if you haven't changed that)

OnUserCommand (nick, data)				[blockable]
	commands that start with + (if you haven't changed that)

OnParsedMsgChat (nick, data)				[blockable]	[special]
	plain chat message - can be blocked
	can also be modified if the return value is a string
	
OnParsedMsgPM (nick, data, receiver)			[blockable]
	private message is being sent
	
OnParsedMsgSearch (nick, data)				[blockable]
	someone runs a search
	example: data == '$Search ip:port F?T?0?9?TTH:YQY3DF.....'  (ip and port belong to nick)

OnParsedMsgValidateNick (nick)				[blockable]
	used during login to check if nick is valid and doesn't contain unwanted characters
	
OnParsedMsgMyINFO (nick, desc, tag, speed, mail, size)	[blockable]	[special]
	called when user sends myinfo - this is what is later appears in the userlist
	you can use normal return values to block it or leave untouched
	or you can return a tuple (desc, tag, speed, mail, size) to modify the message
	each of those fields is a string (or None if you want the field untouched)
	
OnParsedMsgConnectToMe (nick, receiver, ip, port)	[blockable]
	called when nick wants receiver to connect to him on ip:port to initiate a file transfer
	
OnParsedMsgRevConnectToMe (nick, receiver)		[blockable]
	called when a passive user nick wants receiver to send him a file
	soon after that the receiver may send the connecttome message and the script will be called with:
	OnParsedMsgConnectToMe (receiver, nick, ip, port)
	As you can see passive users complicate the task of connection tracking
	You have to store OnParsedMsgRevConnectToMe calls to know who wants to download in the second message

OnParsedMsgAny (nick, data)				[blockable]
	this is called for every message
	afterwards more specialized hooks are called when message gets parsed

OnUnknownMsg (nick, data)
	when a message can't get parsed it ends up here
	
OnOperatorKicks (op, nick, reason)
	called when an operator kicks or bans a user
	warning: reason contains all former kick reasons
	example: reason == 'oldreason\r\nlastreason'
	
OnOperatorDrops (op, nick)
	called after an operator uses !drop command

OnTimer ()
	this hook is called every second - useful for periodical operations

There are also some hooks that are defined but never used by the hub:
	OnNewReg (op, nick, uclass)
	OnNewBan (op, ip, nick, reason)
	OnParsedMsgSupport (nick, data)
	OnParsedMsgMyPass (nick, data)
	OnParsedMsgSR (nick, data)


----------------------------------------------------------------
        Available callbacks:
----------------------------------------------------------------

If not said otherwise, every callback returns 1 on success and 0 on failure

vh.SendDataToUser (data, nick)
	sends a raw message to nick 
	remember to put the '|' character at the end of data

vh.SendDataToAll (data, min_class, max_class)
	sends a raw message to everyone with class within the specified range (it works!)
	remember to put the '|' character at the end of data

vh.SendPMToAll (data, min_class, max_class)
	sends a raw message to everyone with class within the specified range
	remember to put the '|' character at the end of data

vh.mc (data)
	sends a message to all from hub_security 
	no trailing '|' needed
	
vh.classmc (data, min_class, max_class)
	sends a message from hub_security to all within the specified class range
	no trailing '|' needed
	
vh.usermc (data, nick)
	sends a message to nick from hub_security 
	no trailing '|' needed
	
vh.pm (data, nick)
	sends a private message to nick from hub_security 
	no trailing '|' needed
	
vh.CloseConnection (nick)
	does exactly that what's written on the box :)
	
vh.GetRawNickList ()  
	returns a "$NickList nick1$$nick2$$lastnick$$" string

vh.GetNickList ()  
	returns online users in a python list: [ "nick1", "nick2", ... ]

vh.GetRawOpList () 
	returns an "$OpList nick1$$nick2$$lastnick$$" string

vh.GetOpList ()  
	returns online ops in a python list: [ "nick1", "nick2", ... ]
	
vh.GetMyINFO (nick)
	returns a tuple of strings: (nick, desc, tag, speed, mail, size)
	its items are part of the myinfo string: "$MyINFO $ALL nick desc tag$ $speed$mail$size$"

vh.SetMyINFO (nick, desc, tag, speed, mail, size)
	modifies the myinfo string of an online user.
	arguments are strings, if you don't want to change some item put the special object: None instead

vh.ParseCommand (data)  
	not supported yet - does nothing
	
vh.GetUserClass (nick)
	returns 0...10 or -1 (for pingers and if a user is offline)
	you can use SQL queries on the reglist to get results for both online and offline users

vh.GetUserHost (nick)
	returns user's dns

vh.GetUserIP (nick)
	returns user's dns

vh.GetUserCC (nick)
	returns user's 2 letter country code or "--" if there is none or None on failure

vh.KickUser (op, nick, reason)
	makes op kick user nick
	op has to be a real op or hub_security, reason can incude _ban_* to specify ban time
	
vh.Ban (nick, time, type)
	not supported yet - does nothing
	
vh.GetConfig (config, var)
	returns a string with config variable's value or None if this variable can't be found
	This function works for all entries in the SetupList mysql table
	if config is "config", it uses verlihub's internal config variables
	for any other config it uses direct sql access

vh.SetConfig (config, var, val)
	sets variable var to display value represented by the string: val
	
vh.SQL (query, limit)
	queries the verlihub's mysql database using query. 
	optional argument limit > 0 is the maximum number of rows to return. default: 100
	returns a tuple: ( result, data )
	result==1 on success and result==0 on failure
	data is a list of rows and each row is a list of columns
	example: [[row1col1, row1col2, row1col3],[row2col1, row2col2, row2col3]]
	to immediately delete data to free memory after you stopped using it write: del data
	
vh.AddRobot (nick, class, description, speed, email, sharesize)
	adds a fake entry into userlist
	used when you have a script that you want the users to communicate with via private messages
	
vh.DelRobot (nick)
	removes robot from the userlist

vh.GetUsersCount ()
	returns an integer representing the number of online users
	
vh.GetTotalShareSize ()
	returns a string(!!!) with total share of the hub in bytes
	to perform arithmetical operations you have to first convert it to integer using: int( variable )

vh.botname
	returns the nick of hub_security
	
vh.opchatname
	returns the nick of opchat
	
vh.path
	returns full path to the running script
	
vh.name
	returns just the name of the script without the path to it
	
vh.myid
	returns an id number assigned to this script by the plugin - constant untill the script is unloaded
	
vh.starttime
	returns the timeindex at which the hub was started given in seconds from the beginning of year 1970
	you can calculate how many seconds have passed since the hub started using code such as this:
	
	import time
	def uptime(): return int(time.time()) - vh.starttime
	
vh.UserRestrictions (nick, | chat=blockchat, pm=blockpm, search=blocksearch, ctm=blockctm )

	this method allows you to easily check if a user is blocked (gag, nopm, nosearch, noctm)
	it also allows you to set and reset any of those restrictions (see python1.py example script)
	blockchat and similar arguments have the following meaning:
		"0" = unblock, "1" = block for a week/till user reconnects, "30s"/"2h"/"1d" = specify the time yourself
	parameters are passed by keywords, so you can use any of them in any order you like
	
	to block chat and pm:		vh.UserRestrictions(nick, chat="1", pm="1")
	to unblock everything:		vh.UserRestrictions(nick, chat="0", pm="0", search="0", ctm="0")
	to check someone:  	  res = vh.UserRestrictions(nick)
	
	returned object is a dictionary: { "chat":value, "pm":value, "search":value, "ctm":value }
	the only values are "0" or "1" (strings!)
	
vh.Topic ( topic )
	returns hub's current topic, can be also used to set and reset the topic:
	to get the topic: 	t = vh.Topic()
	to delete the topic:	vh.Topic("")
	to set a new topic:	vh.Topic("Owner is out for lunch")

