⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x8004.htm

📁 Its a xmpp protocol book
💻 HTM
📖 第 1 页 / 共 4 页
字号:
>qmacro</I
>
has entered the room (he knows that <I
CLASS="EMPHASIS"
>qmacro</I
> sometimes goes
by the nickname "deejay" and so recognises him), he sends his greetings, and 
<I
CLASS="EMPHASIS"
>qmacro</I
> waves back.</P
><P
><PRE
CLASS="SCREEN"
>RECV: &#60;message to='qmacro@jabber.com/jarltk'
             from='cellar@conf.merlix.dyndns.org/roscoe'
             type='groupchat' cnu=''&#62;
        &#60;body&#62;hi qmacro&#60;/body&#62;
      &#60;/message&#62;

SEND: &#60;message to='cellar@conf.merlix.dyndns.org'
        type='groupchat'&#62;
        &#60;body&#62;/me waves to everyone&#60;/body&#62;
      &#60;/message&#62;&#13;</PRE
></P
><P
>As with the notification message, each message is a "<TT
CLASS="LITERAL"
>groupchat</TT
>"
type message. The one received appears to come from 
<TT
CLASS="LITERAL"
>cellar@conf.merlix.dyndns.org/roscoe</TT
>, which is the JID 
representing the user in the room with the nickname "roscoe". This way, the 
"roscoe"'s real JID is never sent to <I
CLASS="EMPHASIS"
>qmacro</I
>. 
<A
NAME="AEN8170"
HREF="#FTN.AEN8170"
>[3]</A
>
The one sent is addressed to the room's identity 
<TT
CLASS="LITERAL"
>cellar@conf.merlix.dyndns.org</TT
>, and contains a message that
starts with "<I
CLASS="EMPHASIS"
>/me</I
>". This is simply a convention that is 
understood by clients that support conferencing, meant to represent an 
action and displayed thus:</P
><P
><PRE
CLASS="SCREEN"
>* deejay waves to everyone&#13;</PRE
></P
></DD
><DT
>One-on-one chat:</DT
><DD
><P
>The <I
CLASS="EMPHASIS"
>Conferencing</I
> component also supports a one-on-one chat
mode, which is just like normal chat mode (where
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
>s with the type
"<TT
CLASS="LITERAL"
>chat</TT
>"
are exchanged) except that the routing goes through the component. The intended
recipient of a conference-routed chat message is identified by his room JID. So
in this example:</P
><P
><PRE
CLASS="SCREEN"
>RECV: &#60;message to='qmacro@jabber.com/jarltk'
        from='cellar@conf.merlix.dyndns.org/flash'
        type='chat'&#62;
        &#60;body&#62;psst - want to come out for a beer or two?&#60;/body&#62;
        &#60;thread&#62;jarl1998911094&#60;/thread&#62;
      &#60;/message&#62;&#13;</PRE
></P
><P
>The user with the nickname "flash" actually addressed the chat message to the
JID:</P
><P
><PRE
CLASS="SCREEN"
>cellar@conf.merlix.dyndns.org/deejay</PRE
></P
><P
>which arrived at the <I
CLASS="EMPHASIS"
>Conferencing</I
> component
(because of the
hostname "<TT
CLASS="LITERAL"
>conf.merlix.dyndns.org</TT
>" which caused the
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> element to be 
routed there) which then looked up internally who "deejay" really was 
(<TT
CLASS="LITERAL"
>qmacro@jabber.com/jarlrk</TT
>) and sent it on. This way, the
recipient of a conference-routed message never discovers the real JID of the
sender. In all other ways, the actual <TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
>
element is like any other <TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> element&mdash;in
this case it contains a message <TT
CLASS="LITERAL"
>&#60;body/&#62;</TT
> and a 
chat <TT
CLASS="LITERAL"
>&#60;thread/&#62;</TT
>.
<A
NAME="AEN8198"
HREF="#FTN.AEN8198"
>[4]</A
>&#13;</P
></DD
><DT
>Leaving the room:</DT
><DD
><P
>In the same way that room entrance is effected by sending an
<I
CLASS="EMPHASIS"
>available</I
> presence (remember, a
<TT
CLASS="LITERAL"
>&#60;presence/&#62;</TT
> element without an explicit 
<TT
CLASS="LITERAL"
>type</TT
> attribute is understood to represent 
<TT
CLASS="LITERAL"
>type='available'</TT
>), leaving a room is achieved by doing
the opposite&mdash;sending an <I
CLASS="EMPHASIS"
>unavailable</I
> presence
to the room, which is relayed to all the remaining room occupants:</P
><P
><PRE
CLASS="SCREEN"
>RECV: &#60;presence to='qmacro@jabber.com/jarltk' type='unavailable'
              from='cellar@conf.merlix.dyndns.org/roscoe'/&#62;&#13;</PRE
></P
><P
>The fact that "roscoe" left the room is conveyed by the unavailable 
presence packet. This is by and large for the benefit of each user's client,
so that the room occupant list can be updated. The component also sends out
a notification, in the same way as it sends a notification out when someone
joins:</P
><P
><PRE
CLASS="SCREEN"
>RECV: &#60;message to='qmacro@jabber.com/jarltk' type='groupchat'
             from='cellar@conf.merlix.dyndns.org'&#62;
        &#60;body&#62;roscoe has left&#60;/body&#62;
      &#60;/message&#62;&#13;</PRE
></P
><P
>Like the join notification, the text for the leave notification ("has left")
comes directly from the component instance configuration described in
<A
HREF="x1740.htm#JABTDG-CH-4-SECT-4.3.7.3"
>the section called <I
>Custom Configuration</I
> in Chapter 4</A
>.</P
></DD
></DL
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-1.2"
>The script's scope</A
></H2
><P
>We're going to write the script in Python, using the JabberPy library.
What we want the script to do is this:</P
><P
></P
><UL
><LI
><P
>Connect to a pre-determined Jabber server.</P
></LI
><LI
><P
>Join a pre-determined conference room.</P
></LI
><LI
><P
>Sit there quietly, listening to the conversation.</P
></LI
><LI
><P
>Take simple commands from people to watch for, or stop watching for, 
particular words or phrases uttered in the room.</P
></LI
><LI
><P
>Relay the context of those words or phrases to whoever requested them, 
if heard. </P
></LI
></UL
><P
>While we're going to set the identity of the Jabber server and the conference
room into variables in the script, to keep things simple, we'll need to keep
track of which users ask our assistant for what words and phrases. We'll use
a hash ('dictionary' in Python terms) to do this. Having a look at what this
hash will look like during the lifetime of this script will help us to visualize
what we're trying to achieve. <A
HREF="x8004.htm#JABTDG-CH-8-EX-3"
>Example 8-3</A
> shows what the
contents of the hash might look like at any given time.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="JABTDG-CH-8-EX-3"
></A
><P
><B
>Example 8-3. Typical contents of the Keyword assistant's hash</B
></P
><P
><PRE
CLASS="SCREEN"
>{
  'dj@gnu.pipetree.com/home':             {
                                            'http:': 1,
                                            'ftp:': 1
                                          },

  'piers@jabber.org/work':                {
                                            'Perl': 1,
                                            'Java': 1,
                                            'SAP R/3': 1
                                          },

  'cellar@conf.merlix.dyndns.org/roscoe': { 
                                            'Hazzard': 1
                                          }
}&#13;</PRE
></P
></DIV
><P
>We can see from the contents of the hash in <A
HREF="x8004.htm#JABTDG-CH-8-EX-3"
>Example 8-3</A
>
that three people have asked the script to look out for words and phrases. 
Two of those people&mdash;<I
CLASS="EMPHASIS"
>dj</I
> and
<I
CLASS="EMPHASIS"
>piers</I
>&mdash;have interacted with the script directly,
that is by sending the script a 'normal' (or 'chat') 
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
>. The other person, with the 
conference nickname "roscoe", is in the "cellar" room and has sent the script
a message routed through the <I
CLASS="EMPHASIS"
>Conference</I
> component 
in the same way that "flash" sent <I
CLASS="EMPHASIS"
>qmacro</I
> a message
in <A
HREF="x8004.htm#JABTDG-CH-8-EX-2"
>Example 8-2</A
> earlier: the JID of the sender 
belongs to (has the hostname set to) the conference component. Technically
there's nothing to distinguish the three JIDs here, it's just that we know
from the name that <TT
CLASS="LITERAL"
>conf.merlix.dyndns.org</TT
> is the name that
identifies such a component.</P
><P
><I
CLASS="EMPHASIS"
>dj</I
> wants to be notified if any Web or FTP urls are
mentioned.  <I
CLASS="EMPHASIS"
>piers</I
> is interested in references to two
of his favorite languages and his favorite ERP solution, and
<I
CLASS="EMPHASIS"
>roscoe</I
>, well...</P
><P
>We said we'd give the script a little bit of intelligence. This was a
reference to the ability for users to interact with the script while it runs,
rather than have to give the script a static list of words and phrases in a
configuration file. 
<I
CLASS="EMPHASIS"
>dj</I
>, <I
CLASS="EMPHASIS"
>piers</I
> and the user with the 
"roscoe" nickname have all done this, sending the script messages with simple
keyword commands, such as:</P
><P
><P
CLASS="LITERALLAYOUT"
>dj:&nbsp;"<I
CLASS="EMPHASIS"
>watch http:</I
>"<br>
script:&nbsp;"<I
CLASS="EMPHASIS"
>ok, watching for http:</I
>"</P
></P
><P
><P
CLASS="LITERALLAYOUT"
>dj:&nbsp;"<I
CLASS="EMPHASIS"
>watch gopher:</I
>"<br>
script:&nbsp;"<I
CLASS="EMPHASIS"
>ok, watching for gopher:</I
>"</P
></P
><P
><P
CLASS="LITERALLAYOUT"
>dj:&nbsp;"<I
CLASS="EMPHASIS"
>watch ftp:</I
>"<br>
script:&nbsp;"<I
CLASS="EMPHASIS"
>ok, watching for ftp:</I
>"</P
></P
><P
><P
CLASS="LITERALLAYOUT"
>dj:&nbsp;"<I
CLASS="EMPHASIS"
>ignore gopher:</I
>"<br>
script:&nbsp;"<I
CLASS="EMPHASIS"
>ok, now ignoring gopher:</I
>"</P
></P
><P
>...</P
><P
><P
CLASS="LITERALLAYOUT"
>piers:&nbsp;"<I
CLASS="EMPHASIS"
>list</I
>"<br>
script:&nbsp;"<I
CLASS="EMPHASIS"
>watching for: Perl, Java, SAP R/3</I
>"</P
></P
><P
>...</P
><P
><P
CLASS="LITERALLAYOUT"
>roscoe:&nbsp;"<I
CLASS="EMPHASIS"
>stop</I
>"<br>
script:&nbsp;"<I
CLASS="EMPHASIS"
>ok, I've stopped watching</I
>"</P
></P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-1.3"
>Step by step</A
></H2
><P
>Taking the script step by step, the first section is probably familiar if
you've seen the previous Python-based scripts in 
<A
HREF="x6950.htm"
>the section called <I
>CVS notification</I
> in Chapter 7</A
> and <A
HREF="x7499.htm"
>the section called <I
>Presence-sensitive CVS notification</I
> in Chapter 7</A
>.</P
><P
><PRE
CLASS="SCREEN"
>import Jabber, XMLStream
from string import split, join, find
import sys&#13;</PRE
></P
><P
>We bring in all the functions and libraries that we'll be needing. We'll
be using the <TT
CLASS="LITERAL"
>find</TT
> function from the
<TT
CLASS="LITERAL"
>string</TT
> library to help us with our searching.</P
><P
>Next, we declare our hash, or dictionary, which will hold a list of
the words that the script is to look out for, for each person, as shown
in <A
HREF="x8004.htm#JABTDG-CH-8-EX-3"
>Example 8-3</A
>.</P
><P
><PRE
CLASS="SCREEN"
>keywords = {}&#13;</PRE
></P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-8-SECT-1.3.1"
>Maintaining the keyword hash</A
></H3
><P
>To maintain this hash, we need a couple of subroutines that will add
and remove words from a person's individual list. These subroutines 
will be called when a "command" such as "<I
CLASS="EMPHASIS"
>watch</I
>"
or "<I
CLASS="EMPHASIS"
>ignore</I
>" is recognised, in the callback
subroutine that will handle
incoming <TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> elements. </P
><P
>Here are those two subroutines:</P
><P
><PRE
CLASS="SCREEN"
>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]&#13;</PRE
></P
><P
>To each of them, we pass a string representation of the JID (in 
<TT
CLASS="LITERAL"
>jid</TT
>) of the correspondent giving the command,
along with the word or phrase specified (in <TT
CLASS="LITERAL"
>word</TT
>).
The hash has two levels&mdash;the first level is keyed by JID, the second
by word or phrase. We use a hash, rather than an array, at the second
level simply to make removal of words and phrases easier. </P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-8-1.3.2"
>Message callback</A
></H3
><P
>Next, we define our callback to handle incoming 
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> elements. </P
><P
><PRE
CLASS="SCREEN"
>def messageCB(con, msg):

    type = msg.getType()
    if type == None:
        type = 'normal'&#13;</PRE
></P
><P
>As usual, we're expecting our message callback to be passed the 
Jabber <I
CLASS="EMPHASIS"
>Connection</I
> object (in <TT
CLASS="LITERAL"
>con</TT
>)
and the message object itself (in <TT
CLASS="LITERAL"
>msg</TT
>). How this 
callback is to proceed is determined by the <I
CLASS="EMPHASIS"
>type</I
>
of message received. We determine the type (taken from the 
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> element's <TT
CLASS="LITERAL"
>type</TT
>
attribute) and store it in the <TT
CLASS="LITERAL"
>type</TT
> variable. 
Remember that if no <TT
CLASS="LITERAL"
>type</TT
> attribute is present, a
type of "<TT
CLASS="LITERAL"
>normal</TT
>" is assumed. 
<A
NAME="AEN8322"
HREF="#FTN.AEN8322"
>[5]</A
></P
><P
>The two sorts of incoming messages we're expecting this script to receive
are those conveying the room's conversation&mdash;in 
"<TT
CLASS="LITERAL"
>groupchat</TT
>" type messages&mdash;and those over which 
the commands such as "watch" and "ignore" are carried, which we expect in the
form of "<TT
CLASS="LITERAL"
>normal</TT
>" or "<TT
CLASS="LITERAL"
>chat</TT
>" type
messages.</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Incoming commands</DT
><DD
><P
>The first main section of the <TT
CLASS="LITERAL"
>messageCB</TT
> handler 
deals with the incoming commands:</P
><P
><PRE
CLASS="SCREEN"
>    # deal with interaction
    if type == 'chat' or type == 'normal':
        jid = str(msg.getFrom())

        message = split(msg.getBody(), None, 1);
        reply = ""

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -