--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mcabberrc.lua Mon Feb 23 23:23:42 2009 +0200
@@ -0,0 +1,456 @@
+
+
+--[[
+
+DESCRIPTION
+
+This is a demo config file to show, what you can do with lua.
+
+Feature list:
+XEP-0004 Forms parsing and filling
+XEP-0030 Info/items discovery requests (mcabber already can do replies)
+XEP-0047 In-Bound Byte Streams (sending, receiving, saving with specified name, rejecting)
+XEP-0077 In-Band Registration (only registration, but with data forms too)
+XEP-0146 Remote commands requests
+Jobs (actions, fired when some event occurs, now in one file, updated on exit)
+MPD status polling (can be turned off)
+Beep on all messages, even on chatroom ones
+Url saving to file (for urlview)
+Transported buddies availability indication
+Actions on multiple marked buddies
+Fallback commands (localized also! :) )
+Help for fallback commands (well, I know, that it can be done with mcabber's help system, but it requires access to system files...)
+All features have native mcabber interface
+
+REQUIREMENTS
+
+liblua-loudmouth (lm.lua and loudmouth.so)
+liblua-socket - mpd
+
+NOTES
+
+Most hooks get one incoming parameter - hash table with some fields in it.
+This allows further extending and adding arguments without breaking
+previous implementations.
+
+Ibb uses own iq handler. This is the laziest way to implement this.
+
+BUILTINS
+
+print (global) - prints to log
+dofile (global) - loads lua file from default mcabber location
+
+main methods:
+- run - run literal mcabber command
+- beep - beep
+- log - print to log w/specified priority
+- print_info - print info into specified buffer
+- config_file - format full file name from relative to mcabber's config dir
+- status - get current user status and message
+- roster - get list of roster jids (rooms, buddies and agents)
+- current_buddy - get jid of current buddy
+- buddy_info - get table with info about jid and its resources
+- connection - get lightuserdata for mcabber's lm connection
+- timer - run function periodically
+- bgread - run command and read it's output in background
+- add_feature - add string to feature list (for disco#info)
+- del_feature - delete string from feature list
+- add_command - adds mcabber command
+- del_command - remove mcabber command
+
+--]]
+
+-- This is a hack to allow loading of lm.lua and loudmouth.so from ~/.mcabber
+-- instead of installing them system-wide
+package.path = main.config_file ( '?.lua' ) .. ';' .. package.path
+package.cpath = main.config_file ( '?.so' ) .. ';' .. package.cpath
+
+require 'lm'
+
+-- OPTIONS, COMMON SUPPORT ROUTINES
+
+url_file = main.config_file ( 'urls.log' )
+transport_jid = 'icq.jabber.kiev.ua' -- TODO: allow multiple transports
+beep_enable = false
+
+-- XXX: to C?
+char2status = {
+ f = 'free',
+ o = 'online',
+ a = 'away',
+ d = 'dnd',
+ n = 'notavail',
+ i = 'invisible',
+ ['_'] = 'offline',
+ ['?'] = 'message',
+}
+
+function shell_escape ( str )
+ if str then
+ return "'" .. str:gsub ( "'", "'\\''" ) .. "'"
+ else
+ return "''"
+ end
+end
+
+-- This is for debugging purposes, for real reloading need to quote and bracket keys.
+function table_to_string ( tab, pre )
+ local prefix = pre or ""
+ local tbls, jk = "", ""
+
+ for key, val in pairs ( tab ) do
+ if type ( val ) == 'table' then
+ tbls = string.format ( "%s %s%s = %s,\n", tbls, prefix, tostring(key), table_to_string ( val, " " .. prefix ) )
+ else
+ jk = string.format ( "%s %s = %q,", jk, tostring(key), tostring(val) )
+ end
+ end
+
+ if tbls == "" then
+ return string.format ( "{%s }", jk:sub ( 1, -2 ) )
+ else
+ return string.format ( "{%s\n%s%s}", jk, tbls, prefix )
+ end
+end
+
+-- XXX to C?
+function full_current_jid ()
+ local jid = main.current_buddy ()
+ if jid then
+ local info = main.buddy_info ( jid )
+ local prio, resource = 0
+ for res, par in pairs ( info.resources ) do
+ if prio <= par.priority then
+ resource = res
+ prio = par.priority
+ end
+ end
+ if resource then
+ return jid .. '/' .. resource
+ else
+ return jid
+ end
+ else
+ return nil
+ end
+end
+
+-- COMMANDS
+
+function yesno ( value )
+ if value == 'enable' or value == 'yes' or value == 'true' or value == 'on' or value == true then
+ return true
+ elseif value == 'disable' or value == 'no' or value == 'false' or value == 'off' or value == false then
+ return false
+ else
+ return nil
+ end
+end
+
+-- FIXME: eats spaces
+function parse_args ( args )
+ local ret = {}
+ local still_opts = true
+ local optname
+ local option = false
+ for word in args:gmatch ( "%S+" ) do
+ if still_opts and not option and word:sub ( 1, 1 ) == '-' then
+ option = true
+ optname = word:sub ( 2 )
+ elseif option then
+ ret[optname] = word
+ option = false
+ else
+ still_opts = false
+ table.insert ( ret, word )
+ end
+ end
+ return ret
+end
+
+-- Help strings should not contain command, only arguments. This is necessary to support soft aliases.
+commands_help = {
+ file = "filename\n\nSends file as a message. Just shorthand.",
+ s = "status [message]\n\nSets your status, but takes into account mpd (if enabled).",
+ beep = "[enable|disable|on|off|yes|no|true|false]\n\nEnables or disables beeping on all messages.\nIf state is omitted, prints current state.",
+ cmd = "shell_command\n\nRuns shell command in background and sends output to current buddy.\nWorks asynchroneously, and may break long output in the middle of line",
+ exthelp = "[command]\n\nPrints help for a given command, or list of available help topics.",
+ reload = "\n\nJust a shorthand to reload lua config file. Note, that for now this discards all changes to configuration, open forms, transferred files.",
+ ['join!'] = "\n\nForcibly joins to current buddy. Just saves you typing of full room name (that can be quite long) in a case of a non-bookmarked rooms.",
+ count = "\n\nPrints number of resources of current buddy. Useful to determine member count of large room."
+}
+
+main.add_command ( "lua",
+ function ( args )
+ assert ( loadstring ( args ) ) ()
+ end )
+main.add_command ( 'file',
+ function ( args )
+ main.run ( 'say_to -f ' .. args .. ' .' )
+ end )
+main.add_command ( 's',
+ function ( args )
+ main.run ( ('status %s %s'):format ( args, mpd_getstatus () ) )
+ end )
+main.add_command ( 'beep',
+ function ( args )
+ local enable = yesno ( args )
+ if enable == nil then
+ if beep_enable then
+ print ( "Beep on message is enabled" )
+ else
+ print ( "Beep on message is disabled" )
+ end
+ else
+ beep_enable = enable
+ end
+ end )
+main.add_command ( 'cmd',
+ function ( args )
+ local to = main.current_buddy ()
+ main.run ( ('send_to -q %q $ %s'):format ( to, args ) )
+ main.bgread ( args,
+ function ( data )
+ if data then
+ main.run ( ('send_to -q %q %s'):format ( to, data ) )
+ return true
+ else
+ return false
+ end
+ end )
+ end )
+main.add_command ( 'exthelp',
+ function ( args )
+ if commands_help[args] then
+ print ( "\n /" .. args .. ' ' .. commands_help[args] )
+ else
+ print ( "No help for this command." )
+ list = "Help available for commands: "
+ for k in pairs (commands_help) do
+ list = list .. k .. ', '
+ end
+ print ( list:sub ( 1, -3 ) )
+ print ( "For built-in mcabber commands see /help" )
+ end
+ end )
+main.add_command ( 'reload',
+ function ( args )
+ dofile ( main.config_file ( 'mcabberrc.lua' ) )
+ end )
+main.add_command ( 'join!',
+ function ( args )
+ main.run ( 'room join ' .. main.current_buddy () )
+ end )
+main.add_command ( 'count',
+ function ( args )
+ local count = 0
+ for resource in pairs ( main.buddy_info ( main.current_buddy () ).resources ) do
+ count = count + 1
+ end
+ print ( "Resource count: " .. count )
+ end )
+
+for k, arg in ipairs ( { ')', '/', '(', 'D', '-/', 'S', '1', ']', '[' } ) do
+ main.add_command ( arg,
+ function ( args )
+ main.run ( 'say :' .. arg .. ' ' .. args )
+ end )
+end
+
+-- MARKING
+
+dopath 'marking'
+
+-- MPD
+
+dopath 'mpd'
+
+-- FORMS (XEP-0004)
+
+dopath 'xep0004'
+
+-- DISCO (XEP-0030)
+
+dopath 'xep0030'
+
+-- IBB (XEP-0047)
+
+dopath 'xep0047'
+
+-- IN-BAND REGISTRATION (XEP-0077)
+
+dopath 'xep0077'
+
+-- REMOTE CONTROLLING CLIENTS (XEP-0146)
+
+dopath 'xep0146'
+
+-- JOBS
+
+delayed_jobs = {}
+
+-- FIXME: do only if it exists
+dopath 'jobs.lua'
+
+function save_jobs ()
+ local h = io.open ( main.config_file ( 'jobs.lua' ), "w" )
+ if not h then
+ print ( 'Cannot open jobs file for writing!' )
+ return
+ end
+ h:write ( "-- This is autogenerated file, do not edit it manually\n\ndelayed_jobs = {\n" );
+ for jid, more in pairs ( delayed_jobs ) do
+ h:write ( string.format ( "\t[%q] = {\n", jid ) )
+ for status, action in pairs ( more ) do
+ if action then -- remove fired jobs
+ h:write ( string.format ( "\t\t[%q] = %q,\n", status, action ) )
+ end
+ end
+ h:write ( "\t},\n" )
+ end
+ h:write ( "}\n" )
+ h:close ()
+end
+
+main.add_command ( 'delay',
+ function ( args )
+ args = parse_args ( args )
+ local who
+ if args.t then
+ who = args.t
+ args.t = nil
+ else
+ who = main.current_buddy ()
+ end
+ local stat = args[1]
+ args[1] = nil
+ delayed_jobs[who] = { }
+ delayed_jobs[who][stat] =
+ function ()
+ main.run ( 'say_to -q ' .. who .. ' ' .. rebuild_args_string ( args ) )
+ end
+ end )
+
+main.add_command ( 'job',
+ function ( args )
+ local action, jid, stat = args:match ( "(%w+)%s+(%w+)%s+(%w)" )
+ if action == 'del' then
+ delayed_jobs[jid][stat] = nil
+ else
+ print ( 'List of jobs:' )
+ for jid, jobs in pairs ( delayed_jobs ) do
+ for status in pairs ( jobs ) do
+ print ( ' - ' .. jid .. ' -> ' .. status )
+ end
+ end
+ end
+ end )
+
+commands_help['delay'] = "[-t target_jid] status_letter message\n\nDelays sending a message to target jid (or current buddy) until it switches to specified status."
+commands_help['job'] = "[del jid status_letter]\n\nLists available jobs or deletes specified one."
+
+-- HOOKS
+
+ibb_handler_registered = false
+
+-- Soft hooks, implemented through mcabber options
+function hook_post_connect ()
+ main.run ( 'group fold テフノ' )
+ main.run ( 'group fold にゃ' )
+ main.run ( 'group fold にゃ - Друзі' )
+
+ main.run ( 'color muc * on' )
+
+ main.run ( ("color roster * *@%s red"):format ( transport_jid ) )
+ main.run ( ("color roster dn_? *@%s red"):format ( transport_jid ) )
+
+ if mpd_enabled then
+ mpd_callback ()
+ end
+
+ -- FIXME
+ if not ibb_handler_registered then
+ lm.connection.bless( main.connection () ):handler ( ibb_incoming_iq_handler, 'iq', 'normal' )
+ main.add_feature ( 'http://jabber.org/protocol/ibb' )
+ ibb_handler_registered = true
+ end
+end
+
+function hook_pre_disconnect ()
+ main.run ( ("color roster * *@%s white"):format ( transport_jid ) )
+ main.run ( ("color roster dn_? *@%s brightblack"):format ( transport_jid ) )
+end
+
+-- Hard hooks, implemented in C
+
+-- hook
+-- - message_in
+-- jid
+-- groupchat
+-- message
+-- - message_out
+-- jid
+-- message
+-- - status_change
+-- jid
+-- resource
+-- new_status
+-- old_status
+-- message
+-- - my_status_change
+-- new_status
+-- message
+function hook_handler ( args )
+ if args.hook == 'message_in' then
+
+ -- beep on ALL messages, no matter, is it chat or something else.
+ if beep_enable then
+ main.beep ()
+ end
+
+ -- save urls to file from where urlview can get them...
+ for url in args.message:gmatch ( "https?://[%w%p]+" ) do
+ fd = io.open ( url_file, "a" )
+ if fd then
+ fd:write ( url .. "\n" )
+ fd:close ()
+ else
+ print 'Cannot open urls log file'
+ end
+ end
+
+ elseif args.hook == 'status_change' then
+
+ -- delayed actions
+ if delayed_jobs[args.jid] and delayed_jobs[args.jid][args.new_status] then
+ delayed_jobs[args.jid][args.new_status] ()
+ delayed_jobs[args.jid][args.new_status] = nil
+ end
+
+ -- transported buddies availability indication
+ if args.jid == transport_jid then
+ if args.new_status == '_' then
+ main.run ( ("color roster * *@%s red"):format ( transport_jid ) )
+ main.run ( ("color roster dn_? *@%s red"):format ( transport_jid ) )
+ else
+ main.run ( ("color roster * *@%s white"):format ( transport_jid ) )
+ main.run ( ("color roster dn_? *@%s brightblack"):format ( transport_jid ) )
+ end
+ end
+
+ end
+end
+
+-- (hook_start)
+
+function hook_quit ()
+ save_jobs ()
+
+ -- FIXME
+ if ibb_handler_registered then
+ lm.connection.bless( main.connection () ):handler ( ibb_incoming_iq_handler, 'iq' )
+ end
+end
+
+
+-- The End -- vim: se ts=4: --