2 # -*- coding: utf-8 -*-
5 Slixmpp: The Slick XMPP Library
6 Copyright (C) 2010 Nathanael C. Fritz
7 This file is part of Slixmpp.
9 See the file LICENSE for copying permission.
15 from optparse
import OptionParser
19 # Python versions before 3.0 do not use UTF-8 encoding
20 # by default. To ensure that Unicode is handled properly
21 # throughout Slixmpp, we will set the default encoding
23 if sys
.version_info
< (3, 0):
24 from slixmpp
.util
.misc_ops
import setdefaultencoding
25 setdefaultencoding('utf8')
30 class CommandBot(slixmpp
.ClientXMPP
):
33 A simple Slixmpp bot that provides a basic
37 def __init__(self
, jid
, password
):
38 slixmpp
.ClientXMPP
.__init
__(self
, jid
, password
)
40 # The session_start event will be triggered when
41 # the bot establishes its connection with the server
42 # and the XML streams are ready for use. We want to
43 # listen for this event so that we we can initialize
45 self
.add_event_handler("session_start", self
.start
)
47 def start(self
, event
):
49 Process the session_start event.
51 Typical actions for the session_start event are
52 requesting the roster and broadcasting an initial
56 event -- An empty dictionary. The session_start
57 event does not provide any additional
63 # We add the command after session_start has fired
64 # to ensure that the correct full JID is used.
66 # If using a component, may also pass jid keyword parameter.
68 self
['xep_0050'].add_command(node
='greeting',
70 handler
=self
._handle
_command
)
72 def _handle_command(self
, iq
, session
):
74 Respond to the initial request for a command.
77 iq -- The iq stanza containing the command request.
78 session -- A dictionary of data relevant to the command
79 session. Additional, custom data may be saved
80 here to persist across handler callbacks.
82 form
= self
['xep_0004'].makeForm('form', 'Greeting')
83 form
['instructions'] = 'Send a custom greeting to a JID'
84 form
.addField(var
='greeting',
86 label
='Your greeting')
88 session
['payload'] = form
89 session
['next'] = self
._handle
_command
_complete
90 session
['has_next'] = False
92 # Other useful session values:
93 # session['to'] -- The JID that received the
95 # session['from'] -- The JID that sent the
97 # session['has_next'] = True -- There are more steps to complete
98 # session['allow_complete'] = True -- Allow user to finish immediately
99 # and possibly skip steps
100 # session['cancel'] = handler -- Assign a handler for if the user
101 # cancels the command.
102 # session['notes'] = [ -- Add informative notes about the
103 # ('info', 'Info message'), command's results.
104 # ('warning', 'Warning message'),
105 # ('error', 'Error message')]
109 def _handle_command_complete(self
, payload
, session
):
111 Process a command result from the user.
114 payload -- Either a single item, such as a form, or a list
115 of items or forms if more than one form was
116 provided to the user. The payload may be any
117 stanza, such as jabber:x:oob for out of band
118 data, or jabber:x:data for typical data forms.
119 session -- A dictionary of data relevant to the command
120 session. Additional, custom data may be saved
121 here to persist across handler callbacks.
124 # In this case (as is typical), the payload is a form
127 greeting
= form
['values']['greeting']
129 self
.send_message(mto
=session
['from'],
130 mbody
="%s, World!" % greeting
,
133 # Having no return statement is the same as unsetting the 'payload'
134 # and 'next' session values and returning the session.
136 # Unless it is the final step, always return the session dictionary.
138 session
['payload'] = None
139 session
['next'] = None
144 if __name__
== '__main__':
145 # Setup the command line arguments.
146 optp
= OptionParser()
148 # Output verbosity options.
149 optp
.add_option('-q', '--quiet', help='set logging to ERROR',
150 action
='store_const', dest
='loglevel',
151 const
=logging
.ERROR
, default
=logging
.INFO
)
152 optp
.add_option('-d', '--debug', help='set logging to DEBUG',
153 action
='store_const', dest
='loglevel',
154 const
=logging
.DEBUG
, default
=logging
.INFO
)
155 optp
.add_option('-v', '--verbose', help='set logging to COMM',
156 action
='store_const', dest
='loglevel',
157 const
=5, default
=logging
.INFO
)
159 # JID and password options.
160 optp
.add_option("-j", "--jid", dest
="jid",
162 optp
.add_option("-p", "--password", dest
="password",
163 help="password to use")
165 opts
, args
= optp
.parse_args()
168 logging
.basicConfig(level
=opts
.loglevel
,
169 format
='%(levelname)-8s %(message)s')
172 opts
.jid
= raw_input("Username: ")
173 if opts
.password
is None:
174 opts
.password
= getpass
.getpass("Password: ")
176 # Setup the CommandBot and register plugins. Note that while plugins may
177 # have interdependencies, the order in which you register them does
179 xmpp
= CommandBot(opts
.jid
, opts
.password
)
180 xmpp
.register_plugin('xep_0030') # Service Discovery
181 xmpp
.register_plugin('xep_0004') # Data Forms
182 xmpp
.register_plugin('xep_0050') # Adhoc Commands
183 xmpp
.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})
185 # If you are working with an OpenFire server, you may need
186 # to adjust the SSL version used:
187 # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
189 # If you want to verify the SSL certificates offered by a server:
190 # xmpp.ca_certs = "path/to/ca/cert"
192 # Connect to the XMPP server and start processing XMPP stanzas.
194 # If you do not have the dnspython library installed, you will need
195 # to manually specify the name of the server if it does not match
196 # the one in the JID. For example, to use Google Talk you would
199 # if xmpp.connect(('talk.google.com', 5222)):
201 xmpp
.process(block
=True)
204 print("Unable to connect.")