📄 x8004.htm
字号:
CLASS="SCREEN"
>SEND: <message to='jdev@conference.jabber.org/qmacro'>
<body>Hello there</body>
</message>
RECV: <message to='dj@gnu.mine.nu/jarl'
from='jdev@conference.jabber.org/qmacro' type='error'>
<body>Hello there</body>
<error code='404'>Not Found</error>
</message> </PRE
></P
></DIV
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-8-SECT-1.3.4"
>The main script</A
></H3
><P
>Ok. We've got our subroutines and callbacks set up. All that remains
is for us to define our Jabber server and room information:</P
><P
><PRE
CLASS="SCREEN"
>Server = 'gnu.mine.nu'
Username = 'kassist'
Password = 'pass'
Resource = 'py'
Room = 'jdev'
ConfServ = 'conference.jabber.org'
Nick = 'kassist' </PRE
></P
><P
>The <TT
CLASS="LITERAL"
>kassist</TT
> user can be set up simply by using the
<B
CLASS="COMMAND"
>reguser</B
> script presented in
<A
HREF="x6787.htm"
>the section called <I
>User Registration Script</I
> in Chapter 6</A
>:</P
><P
><PRE
CLASS="SCREEN"
>$ <TT
CLASS="USERINPUT"
><B
>./reguser gnu.mine.nu username=kassist password=pass</B
></TT
>
[Attempt] (kassist) Successful registration
$ </PRE
></P
><P
>In the same way as previous recipes' scripts, a connection attempt, followed
by an authentication attempt, is made:</P
><P
><PRE
CLASS="SCREEN"
>con = Jabber.Connection(host=Server,debug=0,log=0)
try:
con.connect()
except XMLStream.error, e:
print "Couldn't connect: %s" % e
sys.exit(0)
else:
print "Connected"
if con.auth(Username,Password,Resource):
print "Logged in as %s to server %s" % ( Username, Server )
else:
print "problems authenticating: ", con.lastErr, con.lastErrCode
sys.exit(1) </PRE
></P
><P
>Then the message and presence callbacks <TT
CLASS="FUNCTION"
>messageCB()</TT
>
and <TT
CLASS="FUNCTION"
>presenceCB()</TT
> are defined to our
<TT
CLASS="LITERAL"
>Connection</TT
> object <TT
CLASS="LITERAL"
>con</TT
>:</P
><P
><PRE
CLASS="SCREEN"
>con.setMessageHandler(messageCB)
con.setPresenceHandler(presenceCB) </PRE
></P
><P
>After sending initial presence, informing the JSM (and anyone that
might be subscribed to <TT
CLASS="LITERAL"
>kassist</TT
>'s presence) of our
availability:</P
><P
><PRE
CLASS="SCREEN"
>con.send(Jabber.Presence()) </PRE
></P
><P
>we also construct—from the
<TT
CLASS="LITERAL"
>Room</TT
>, <TT
CLASS="LITERAL"
>ConfServ</TT
>, and
<TT
CLASS="LITERAL"
>Nick</TT
> variables—and send
the <TT
CLASS="LITERAL"
><presence/></TT
> element for negotiating
entry to the "jdev" room hosted by the <I
CLASS="EMPHASIS"
>Conferencing</I
>
component at <TT
CLASS="LITERAL"
>conference.jabber.org</TT
>:</P
><P
><PRE
CLASS="SCREEN"
>roomjid = Room + '@' + ConfServ + '/' + Nick
print "Joining " + Room
con.send(Jabber.Presence(to=roomjid)) </PRE
></P
><P
><TT
CLASS="FUNCTION"
>con.send()</TT
> will send a
<TT
CLASS="LITERAL"
><presence/></TT
> element that looks like
this:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence to='jdev@conference.jabber.org/kassist'/></PRE
></P
><P
>We're sending available presence to the room, to negotiate entry, but
what about the initial presence? Why do we send that too, as there
are no users that are likely to be subscribed to the <TT
CLASS="LITERAL"
>kassist</TT
>
JID.
Well, if no initial presence is sent, the JSM will merely store up any
<TT
CLASS="LITERAL"
><message/></TT
> elements destined for
<TT
CLASS="LITERAL"
>kassist</TT
>, as
it will think the JID is offline. That won't help at all. </P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-3-SECT-1.3.5"
>The processing loop</A
></H3
><P
>Once everything has been set up: initial presence has been sent and the
room has been entered, we simply need to have the script sit back, wait
for incoming packets, and handle them appropriately. For this, we simply
call the <TT
CLASS="FUNCTION"
>process()</TT
> repeatedly, waiting up to 5
seconds at a time for elements to arrive on the XML stream:</P
><P
><PRE
CLASS="SCREEN"
>while(1):
con.process(5) </PRE
></P
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-1.4"
>The whole script</A
></H2
><P
>Here's the Keyword assistant script in its entirety.</P
><P
><PRE
CLASS="SCREEN"
>import Jabber, XMLStream
from string import split, join, find
import sys
keywords = {}
def addword(jid, word):
if not keywords.has_key(jid):
keywords[jid] = {}
keywords[jid][word] = 1
def delword(jid, word):
if keywords.has_key(jid):
if keywords[jid].has_key(word):
del keywords[jid][word]
def messageCB(con, msg):
type = msg.getType()
if type == None:
type = 'normal'
# deal with interaction
if type == 'chat' or type == 'normal':
jid = str(msg.getFrom())
message = split(msg.getBody(), None, 1);
reply = ""
if message[0] == 'watch':
addword(jid, message[1])
reply = "ok, watching for " + message[1]
if message[0] == 'ignore':
delword(jid, message[1])
reply = "ok, now ignoring " + message[1]
if message[0] == 'list':
if keywords.has_key(jid):
reply = "watching for: " + join(keywords[jid].keys(), ", ")
else:
reply = "not watching for any keywords"
if message[0] == 'stop':
if keywords.has_key(jid):
del keywords[jid]
reply = "ok, I've stopped watching"
if reply:
con.send(msg.build_reply(reply))
# scan room talk
if type == 'groupchat':
message = msg.getBody()
for jid in keywords.keys():
for word in keywords[jid].keys():
if find(message, word) >= 0:
con.send(Jabber.Message(jid, word + ": " + message))
def presenceCB(con, prs):
# deal with nickname conflict in room
if str(prs.getFrom()) == roomjid and prs.getType() == 'error':
prsnode = prs.asNode()
error = prsnode.getTag('error')
if error:
if (error.getAttr('code') == '409'):
print "cannot join room - conflicting nickname"
con.disconnect()
sys.exit(0)
# remove keyword list for groupchat correspondent
if prs.getType() == 'unavailable':
jid = str(prs.getFrom())
if keywords.has_key(jid):
del keywords[jid]
Server = 'gnu.mine.nu'
Username = 'kassist'
Password = 'pass'
Resource = 'py'
Room = 'jdev'
ConfServ = 'conference.jabber.org'
Nick = 'kassist'
con = Jabber.Connection(host=Server,debug=0,log=0)
try:
con.connect()
except XMLStream.error, e:
print "Couldn't connect: %s" % e
sys.exit(0)
else:
print "Connected"
if con.auth(Username,Password,Resource):
print "Logged in as %s to server %s" % ( Username, Server )
else:
print "problems authenticating: ", con.lastErr, con.lastErrCode
sys.exit(1)
con.setMessageHandler(messageCB)
con.setPresenceHandler(presenceCB)
con.send(Jabber.Presence())
roomjid = Room + '@' + ConfServ + '/' + Nick
print "Joining " + Room
con.send(Jabber.Presence(to=roomjid))
while(1):
con.process(5) </PRE
></P
></DIV
></DIV
><H3
CLASS="FOOTNOTES"
>Notes</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8029"
HREF="x8004.htm#AEN8029"
>[1]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>There is also a third protocol, called "Experimental iq:groupchat", which came
inbetween the <I
CLASS="EMPHASIS"
>Groupchat</I
> and <I
CLASS="EMPHASIS"
>Conference</I
>
protocols. This reflected an experimental move to adding features to the basic
<I
CLASS="EMPHASIS"
>Groupchat</I
> protocol by the use of IQ elements, the contents
of which were qualified by a namespace "<TT
CLASS="LITERAL"
>jabber:iq:groupchat</TT
>".
This protocol has been dropped, and support for it only exists in certain versions
of a couple of public Jabber clients - <B
CLASS="COMMAND"
>WinJab</B
> and
<B
CLASS="COMMAND"
>JIM</B
>.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8134"
HREF="x8004.htm#AEN8134"
>[2]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>There's no rule that says the nickname can't be the same as the user part of
your JID, if you're not concerned with hiding your true identity :-)</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8170"
HREF="x8004.htm#AEN8170"
>[3]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>Ignore the <TT
CLASS="LITERAL"
>cnu</TT
> attribute. It's put there by the component,
and should never make it out to the client endpoints. The attribute name is
a short name for "conference user", and refers to the internal structure that
represents a conference room occupant within the component.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8198"
HREF="x8004.htm#AEN8198"
>[4]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>See <A
HREF="x4089.htm#JABTDG-CH-5-SECT-5.4.1"
>the section called <I
>The Message Element</I
> in Chapter 5</A
> for details on the
<TT
CLASS="LITERAL"
><message/></TT
> element.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8322"
HREF="x8004.htm#AEN8322"
>[5]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>See <A
HREF="x4089.htm#JABTDG-CH-5-SECT-5.4.1.1"
>the section called <I
>Message Attributes</I
> in Chapter 5</A
> for details of
<TT
CLASS="LITERAL"
><message/></TT
> attributes.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8446"
HREF="x8004.htm#AEN8446"
>[6]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>If this seems a little cryptic, just think of it like this: each of the
<TT
CLASS="LITERAL"
>Presence</TT
>, <TT
CLASS="LITERAL"
>Message</TT
>, and
<TT
CLASS="LITERAL"
>IQ</TT
> classes are merely superclasses of the base class
<TT
CLASS="LITERAL"
>Protocol</TT
>, which represents elements generically.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8462"
HREF="x8004.htm#AEN8462"
>[7]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>By the <TT
CLASS="LITERAL"
>mod_offline</TT
> module of the Jabber Session Manager
(JSM).</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN8498"
HREF="x8004.htm#AEN8498"
>[8]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>Of course, if the JID referred to a non-existent Jabber server, then the
error returned wouldn't be a "<I
CLASS="EMPHASIS"
>Not Found</I
>" error 404,
but an "<I
CLASS="EMPHASIS"
>Unable to resolve hostname</I
>" error 502.</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c7982.htm"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.htm"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="x8561.htm"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Extending Messages, Groupchat, Components, and Event Models</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c7982.htm"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Any coffee left?</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -