📄 x8004.htm
字号:
<HTML
><HEAD
><TITLE
>Keyword assistant</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="HOME"
TITLE="Programming Jabber"
HREF="book1.htm"><LINK
REL="UP"
TITLE="Extending Messages, Groupchat, Components, and Event Models"
HREF="c7982.htm"><LINK
REL="PREVIOUS"
TITLE="Extending Messages, Groupchat, Components, and Event Models"
HREF="c7982.htm"><LINK
REL="NEXT"
TITLE="Any coffee left?"
HREF="x8561.htm"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming Jabber</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c7982.htm"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 8. Extending Messages, Groupchat, Components, and Event Models</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="x8561.htm"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="JABTDG-CH-8-SECT-1"
>Keyword assistant</A
></H1
><P
>Many of the Jabber core and peripheral developers hang out in a conference
room called "jdev" hosted by the <I
CLASS="EMPHASIS"
>Conferencing</I
> component
on the Jabber server running at
<TT
CLASS="LITERAL"
>jabber.org</TT
>. While a lot of useful information was to be
gleaned from listening to what went on in "jdev", it wasn't possible for me
to be there all the time. The conversations in "jdev" were logged to web pages,
which I used to visit after the fact to try and catch up with things. This was
mostly a hopeless task, so I decided to try and improve the situation
slightly by looking for keywords and Uniform Resource Locators (URLs)
in those logs. </P
><P
>This recipe is an automated version of what I did manually. It is a script that
connects to a Jabber server, enters a conference room, and sits quite still,
listening to the conversation and letting me know when certain words or phrases
were uttered. I've given the script a bit of "intelligence" in that it can be
interacted with, and told, while running, to watch for, or stop watching for,
words and phrases of our choosing.</P
><P
>The script introduces us to programmatic interaction with the
<I
CLASS="EMPHASIS"
>Conferencing</I
> component. Before looking at the script,
let's have a brief overview of <I
CLASS="EMPHASIS"
>Conferencing</I
> in
general.</P
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-1.1"
>Conferencing</A
></H2
><P
>The <I
CLASS="EMPHASIS"
>Conferencing</I
> component at <TT
CLASS="LITERAL"
>jabber.org</TT
>
has the name <TT
CLASS="LITERAL"
>conference.jabber.org</TT
>.
Details of the component instance configuration for such a
<I
CLASS="EMPHASIS"
>Conferencing</I
> component can be found in
<A
HREF="x1740.htm#JABTDG-CH-4-SECT-4.3.7"
>the section called <I
>Component Instance: <I
CLASS="EMPHASIS"
>conf</I
></I
> in Chapter 4</A
>, where we see that the component
exists as a shared object library connected with the
<I
CLASS="EMPHASIS"
>library load</I
> component connection method. This
component provides general conferencing facilities, orientated around a
conference <I
CLASS="EMPHASIS"
>room</I
> and conference <I
CLASS="EMPHASIS"
>user</I
>
model.</P
><P
>A Jabber user can "enter" (or "join") a conference <I
CLASS="EMPHASIS"
>room</I
>
and thereby becomes a conference <I
CLASS="EMPHASIS"
>user</I
> identified by a
nickname that is chosen upon entering that room. Nicknames are generally used
in conference rooms to provide a modicum of privacy—it is assumed that by
default you don't want to let the other conference room members know your real
JID.</P
><P
>The <I
CLASS="EMPHASIS"
>Conferencing</I
> component that is currently available
for use with the Jabber 1.4.1 server supports
two protocols for user and room interaction; a simple one that provides basic
features, and a more complex one that provides the basic features plus
facilities such as password-protected rooms, and room descriptions:
<A
NAME="AEN8029"
HREF="#FTN.AEN8029"
>[1]</A
></P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Groupchat</DT
><DD
><P
>The <I
CLASS="EMPHASIS"
>Groupchat</I
> protocol is the simpler of the two and
provides basic functions for entering and exiting conference rooms, and
choosing nicknames.</P
><P
>This <I
CLASS="EMPHASIS"
>Groupchat</I
> protocol has a nominal protocol version
number of 1.0. It is known as the "presence-based" protocol, because the
protocol is based upon <TT
CLASS="LITERAL"
><presence/></TT
> elements
that are used for room entry, exit, and nickname determination.</P
></DD
><DT
>Conference</DT
><DD
><P
>The <I
CLASS="EMPHASIS"
>Conference</I
> protocol offers more advanced features
than the <I
CLASS="EMPHASIS"
>Groupchat</I
> protocol and makes use of two IQ
namespaces—<TT
CLASS="LITERAL"
>jabber:iq:conference</TT
> and
<TT
CLASS="LITERAL"
>jabber:iq:browse</TT
>. It has a nominal protocol version
number of 1.4 which reflects the version of the Jabber server with which
it is delivered. Sometimes this version number is referred to as 0.4, such
as in the downloadable tarball, and in the value returned in response to a
"version query" on the component itself, as shown in
<A
HREF="x8004.htm#JABTDG-CH-8-EX-1"
>Example 8-1</A
>.</P
><P
>The version number isn't that important. The main thing to note is that
the component that is called "<TT
CLASS="LITERAL"
>conference.so</TT
>" (see
the reference to the shared object library in
<A
HREF="x1740.htm#JABTDG-CH-4-SECT-4.3.7.4"
>the section called <I
>Component Connection Method</I
> in Chapter 4</A
>) supports both the
<I
CLASS="EMPHASIS"
>Groupchat</I
> protocol and the <I
CLASS="EMPHASIS"
>Conference</I
>
protocol. If you come across a shared object library called
<TT
CLASS="LITERAL"
>groupchat.so</TT
>, this is the original
<I
CLASS="EMPHASIS"
>Conferencing</I
> component that was made available with Jabber
server version 1.0. This library only supports the <I
CLASS="EMPHASIS"
>Groupchat</I
>
protocol.</P
></DD
></DL
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="JABTDG-CH-8-EX-1"
></A
><P
><B
>Example 8-1. Querying the <I
CLASS="EMPHASIS"
>Conferencing</I
> component's version</B
></P
><P
><PRE
CLASS="SCREEN"
>SEND: <iq type='get' to='conference.gnu.mine.nu'>
<query xmlns='jabber:iq:version'/>
</iq>
RECV: <iq to='dj@gnu.mine.nu/jarl' from='conference.gnu.mine.nu'
type='result'>
<query xmlns='jabber:iq:version'>
<name>conference</name>
<version>0.4</version>
<os>Linux 2.4.2-2</os>
</query>
</iq></PRE
></P
></DIV
><P
>In this recipe we'll be using the simpler "Groupchat" protocol. It's widely used,
and easy to understand. <A
HREF="x8004.htm#JABTDG-CH-8-EX-2"
>Example 8-2</A
> shows a typical
element log from Groupchat-based activity. It shows a user, with the JID
<TT
CLASS="LITERAL"
>qmacro@jabber.com</TT
>, entering a room called "cellar", hosted
on the conference component at <TT
CLASS="LITERAL"
>conf.merlix.dyndns.org</TT
>,
a room which
currently has two other occupants who go by the nicknames "flash" and "roscoe".
The elements are from <I
CLASS="EMPHASIS"
>qmacro</I
>'s perspective.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="JABTDG-CH-8-EX-2"
></A
><P
><B
>Example 8-2. The Groupchat protocol in action</B
></P
><P
><I
CLASS="EMPHASIS"
>qmacro</I
> tries to enter the room with the nickname "flash",
and fails:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence to='cellar@conf.merlix.dyndns.org/flash'/>
RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/flash'
type='error'>
<error code='409'>Conflict</error>
</presence> </PRE
></P
><P
>He tries again, this time with a different nickname "deejay". Success:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence to='cellar@conf.merlix.dyndns.org/deejay'/>
RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/flash'/>
RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/roscoe'/>
RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/deejay'/>
RECV: <message to='qmacro@jabber.com/jarltk'
type='groupchat' from='cellar@conf.merlix.dyndns.org'>
<body>qmacro has become available</body>
</message> </PRE
></P
><P
>"roscoe" says hi, and <I
CLASS="EMPHASIS"
>qmacro</I
> waves back:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <message to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/roscoe'
type='groupchat' cnu=''>
<body>hi qmacro</body>
</message>
SEND: <message to='cellar@conf.merlix.dyndns.org' type='groupchat'>
<body>/me waves to everyone</body>
</message> </PRE
></P
><P
>"flash" sends <I
CLASS="EMPHASIS"
>qmacro</I
> a private message:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <message to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/flash'
type='chat'>
<body>psst - want to come out for a beer or two?</body>
<thread>jarl1998911094</thread>
</message> </PRE
></P
><P
>"roscoe" leaves the room:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <presence to='qmacro@jabber.com/jarltk' type='unavailable'
from='cellar@conf.merlix.dyndns.org/roscoe'/>
RECV: <message to='qmacro@jabber.com/jarltk' type='groupchat'
from='cellar@conf.merlix.dyndns.org'>
<body>roscoe has left</body>
</message></PRE
></P
></DIV
><P
>Let's take the elements in <A
HREF="x8004.htm#JABTDG-CH-8-EX-2"
>Example 8-2</A
> bit by bit.</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Failed attempt to enter room:</DT
><DD
><P
><I
CLASS="EMPHASIS"
>qmacro</I
> makes an attempt to enter the room using the
<I
CLASS="EMPHASIS"
>Groupchat</I
> protocol. This is done by sending a directed
<TT
CLASS="LITERAL"
><presence/></TT
> element to a particular JID that
represents the room and the chosen nickname. This JID is constructed as
follows:</P
><P
><PRE
CLASS="SCREEN"
>[room name]@[conference component]/[nickname]</PRE
></P
><P
>In this example, the conferencing component is identified with the
hostname <TT
CLASS="LITERAL"
>conf.merlix.dyndns.org</TT
>. <I
CLASS="EMPHASIS"
>qmacro</I
>'s
choice of nickname is "flash", determining that the JID, to which available
presence should be sent, be:</P
><P
><PRE
CLASS="SCREEN"
>cellar@conf.merlix.dyndns.org/flash</PRE
></P
><P
>Thus the following element is sent:</P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence to='cellar@conf.merlix.dyndns.org/flash'/> </PRE
></P
><P
>The conference component determines that there is already someone present
in the room <TT
CLASS="LITERAL"
>cellar@conf.merlix.dyndns.org</TT
> with the nickname
"flash", and so notifies <I
CLASS="EMPHASIS"
>qmacro</I
> by sending back a
directed presence with an <TT
CLASS="LITERAL"
><error/></TT
> tag:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/flash'
type='error'>
<error code='409'>Conflict</error>
</presence> </PRE
></P
><P
>Note that the <TT
CLASS="LITERAL"
><presence/></TT
> element has the
type "<TT
CLASS="LITERAL"
>error</TT
>", and comes <TT
CLASS="FILENAME"
>from</TT
> the
artificial JID that we constructed in our room entry attempt. The
element is addressed to our real JID, of
course—<TT
CLASS="LITERAL"
>qmacro@jabber.com/jarltk</TT
>—as otherwise
it wouldn't reach us. </P
><P
>The error code 409 and text "Conflict" tells <I
CLASS="EMPHASIS"
>qmacro</I
>
that the nickname conflicted with one already in the room. This is a standard
error code/text pair; <A
HREF="x4089.htm#JABTDG-CH-5-TAB-3"
>Table 5-3</A
> shows a complete
set of code/text pairs. </P
><P
>At this stage, <I
CLASS="EMPHASIS"
>qmacro</I
> is not yet in the room.</P
></DD
><DT
>Successful attempt to enter room:</DT
><DD
><P
><I
CLASS="EMPHASIS"
>qmacro</I
> tries again, this time with a different nickname
"deejay":
<A
NAME="AEN8134"
HREF="#FTN.AEN8134"
>[2]</A
> </P
><P
><PRE
CLASS="SCREEN"
>SEND: <presence to='cellar@conf.merlix.dyndns.org/deejay'/> </PRE
></P
><P
>This time, there is no conflict—no other user is in the room "cellar" with
that nickname—and the conference component registers the entry. It
does this by sending <I
CLASS="EMPHASIS"
>qmacro</I
> the presence of all the
room occupants, including that of himself as "deejay":</P
><P
><PRE
CLASS="SCREEN"
>RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/flash'/>
RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/roscoe'/>
RECV: <presence to='qmacro@jabber.com/jarltk'
from='cellar@conf.merlix.dyndns.org/deejay'/> </PRE
></P
><P
>These presence elements are also sent to the other room occupants.</P
></DD
><DT
>Conference component-generated notification:</DT
><DD
><P
>In addition to the presence elements sent for each room occupant, a general
room-wide message noting that someone with the nickname
"deejay" just entered the room, is sent out by the component as a
<TT
CLASS="LITERAL"
>type='groupchat'</TT
> message to all the room occupants.
Like all the other people, <I
CLASS="EMPHASIS"
>qmacro</I
> receives it:</P
><P
><PRE
CLASS="SCREEN"
>RECV: <message to='qmacro@jabber.com/jarltk'
type='groupchat'
from='cellar@conf.merlix.dyndns.org'>
<body>qmacro has become available</body>
</message> </PRE
></P
><P
>The text "has become available" used in the body of the message is taken directly
from the <I
CLASS="EMPHASIS"
>Action Notices</I
> definitions, part of the
<I
CLASS="EMPHASIS"
>Conferencing</I
> 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
>. Note that the identity of the room
itself is simply a generic version of the JID that the room occupants use to
enter:</P
><P
><PRE
CLASS="SCREEN"
>cellar@conf.merlix.dyndns.org </PRE
></P
></DD
><DT
>Room-wide chat:</DT
><DD
><P
>Once the user with the nickname "roscoe" sees that <I
CLASS="EMPHASIS"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -