?? x6950.htm
字號:
> suffix) resemble email IDs, there doesn't
appear to be that much difference. In any case, CVS doesn't really care,
and simply passes the portion following the colon separator to the
formula in the <TT
CLASS="FILENAME"
>notify</TT
> file.</P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-7-SECT-1.3"
>The <TT
CLASS="LITERAL"
>cvsmsg</TT
> notification script</A
></H2
><P
>Let's now have a look at the <TT
CLASS="LITERAL"
>cvsmsg</TT
> script. It
has to send a notification message, which it receives on STDIN, to
a JID, which it receives as an argument passed to the script.</P
><P
><PRE
CLASS="SCREEN"
>import Jabber, XMLStream
import sys </PRE
></P
><P
>We're going to use the <I
CLASS="EMPHASIS"
>JabberPy</I
> Python libraries
for Jabber
<A
NAME="AEN7118"
HREF="#FTN.AEN7118"
>[3]</A
>
so we import them here. As is the way with many implementations for
Jabber, we find there is a module to handle the XML stream-based connection
with the Jabber server (the <TT
CLASS="LITERAL"
>XMLStream</TT
> module) and
a module to handle the various Jabber connection mechanisms such as
authentication, the sending of Jabber elements
(<TT
CLASS="LITERAL"
><message/></TT
>,
<TT
CLASS="LITERAL"
><presence/></TT
>,
and <TT
CLASS="LITERAL"
><iq/></TT
>),
and the dispatching of Jabber elements received (the
<TT
CLASS="LITERAL"
>Jabber</TT
> module).
We also import the <TT
CLASS="LITERAL"
>sys</TT
> module for reading from STDIN.</P
><P
>As the usage of the script will be fairly static, we can get away here with
hardcoding a few parameters:</P
><P
><PRE
CLASS="SCREEN"
>Server = 'gnu.pipetree.com'
Username = 'cvsmsg'
Password = 'secret'
Resource = 'cvsmsg' </PRE
></P
><P
>Specified here are the connection and authentication details for the
<TT
CLASS="LITERAL"
>cvsmsg</TT
> script itself. If it's to send a message via
Jabber, it must itself connect to Jabber. The <TT
CLASS="LITERAL"
>Server</TT
>
variable specifies which Jabber server to connect to, and the
<TT
CLASS="LITERAL"
>Username</TT
>, <TT
CLASS="LITERAL"
>Password</TT
>, and
<TT
CLASS="LITERAL"
>Resource</TT
> variables contain the rest of the information
for the script's own JID (<TT
CLASS="LITERAL"
>cvsmsg@gnu.pipetree.com/cvsmsg</TT
>)
and password.</P
><P
><PRE
CLASS="SCREEN"
>cvsuser = sys.argv[1]
message = ''
for line in sys.stdin.readlines(): message = message + line </PRE
></P
><P
>The <TT
CLASS="LITERAL"
>sys.argv[1]</TT
> refers to the notification recipient's
JID, which will be specified by the CVS notification mechanism, as it is
substituted for the <TT
CLASS="LITERAL"
>%s</TT
> in the <TT
CLASS="FILENAME"
>notify</TT
>
file's formula. This is saved in the <TT
CLASS="LITERAL"
>cvsuser</TT
> variable.
We then build up the content of our message body we're going to send via
Jabber by reading what's available on STDIN. Typically this will look
like what we saw in the email message body in
<A
HREF="x6950.htm#JABTDG-CH-7-FIG-1"
>Figure 7-1</A
>:</P
><P
><PRE
CLASS="SCREEN"
>testproject file4
---
Triggered edit watch on /usr/local/cvsroot/testproject
By piers</PRE
></P
><P
><PRE
CLASS="SCREEN"
>con = Jabber.Connection(host=Server) </PRE
></P
><P
>Although it is the <TT
CLASS="LITERAL"
>XMLStream</TT
> module that handles
the connection to the Jabber server, we are shielded from the details
of this by the <TT
CLASS="LITERAL"
>Jabber</TT
> module that wraps and uses
<TT
CLASS="LITERAL"
>XMLStream</TT
>. Hence the call to instantiate a new
<TT
CLASS="LITERAL"
>Jabber.Connection</TT
> object into <TT
CLASS="LITERAL"
>con</TT
>,
to lay the way for our connection to the host specified in our Server
variable:
<TT
CLASS="LITERAL"
>gnu.pipetree.com</TT
>. No port is explicitly specified
here, and the method assumes a default port of 5222, on which the
<I
CLASS="EMPHASIS"
>c2s</I
> service listens.</P
><P
>The instantiation causes a number of parameters and variables to be
initialized, and an <TT
CLASS="LITERAL"
>XMLStream.Client</TT
> object is
instantiated; various parameters are passed through from the
<TT
CLASS="LITERAL"
>Jabber.Connection</TT
> object (for example for logging
and debugging purposes) and an XML parser object is instantiated.
This will be used to parse fragments of XML that come in over the
XML stream.</P
><P
><PRE
CLASS="SCREEN"
>try:
con.connect()
except XMLStream.error, e:
print "Couldn't connect: %s" % e
sys.exit(0) </PRE
></P
><P
>A connection is attempted with the <TT
CLASS="LITERAL"
>connect()</TT
> method
of the connection object in <TT
CLASS="LITERAL"
>con</TT
>. This is serviced by
the <TT
CLASS="LITERAL"
>XMLStream.Client</TT
> object and a stream header, as
described in <A
HREF="x3837.htm"
>the section called <I
>XML Streams</I
> in Chapter 5</A
>, is sent to
<TT
CLASS="LITERAL"
>gnu.pipetree.com:5222</TT
> in an a attempt to establish a
client connection.</P
><P
>XMLStream will raise an error if the connection cannot be established, we
trap this, after a fashion, with the <TT
CLASS="LITERAL"
>try: ... except</TT
>
shown here.</P
><P
><PRE
CLASS="SCREEN"
>con.auth(Username,Password,Resource)</PRE
></P
><P
>Once we're connected—our client has successfully exchanged XML
stream headers with the server—we need to authenticate. The
<TT
CLASS="LITERAL"
>auth</TT
> method of the <TT
CLASS="LITERAL"
>Jabber.Connection</TT
>
object provides us with a simple way of carrying out the authentication
negotiation, qualified with the <TT
CLASS="LITERAL"
>jabber:iq:auth</TT
> namespace
and described in detail in <A
HREF="x6569.htm"
>the section called <I
>User Authentication</I
> in Chapter 6</A
>.
Although we supply our password here in the script in plaintext
('<TT
CLASS="LITERAL"
>secret</TT
>'), the <TT
CLASS="LITERAL"
>auth</TT
> method will
use the IQ-get (<TT
CLASS="LITERAL"
><iq type='get'...></TT
>) to retrieve
a list of authentication methods supported by the server. It will try and
use the most secure, "gracefully degrading" to the least, until it finds
one that is supported.
<A
NAME="AEN7180"
HREF="#FTN.AEN7180"
>[4]</A
></P
><P
>Note the presence of the <TT
CLASS="LITERAL"
>resource</TT
> in the call. This
is required for a successful client authentication regardless of the
authentication method. Sending an IQ-set
(<TT
CLASS="LITERAL"
><iq type='set'...></TT
>)
in the <TT
CLASS="LITERAL"
>jabber:iq:auth</TT
> namespace without
specifying a value in a<TT
CLASS="LITERAL"
><resource/></TT
> tag
results in a "Not Acceptable" error 406; see <A
HREF="x4089.htm#JABTDG-CH-5-TAB-3"
>Table 5-3</A
>
for a list of standard error codes and texts.</P
><P
>We're connected, and authenticated. The world is now our lobster, as
an old friend used to say. We're not necessarily <I
CLASS="EMPHASIS"
>expecting</I
>
to receive anything at this stage, and even if we did, we wouldn't really
want to do anything with what we received anyway. At least at this stage.
So we don't bother setting up any mechanism for handling elements that
might appear on the stream. </P
><P
><PRE
CLASS="SCREEN"
>con.send(Jabber.Message(cvsuser, message, subject="CVS Watch Alarm"))</PRE
></P
><P
>All we do is send the notification message, in the <TT
CLASS="LITERAL"
>message</TT
>
variable, to the user that was specified as an argument when the script
was invoked, stored in the <TT
CLASS="LITERAL"
>cvsuser</TT
> variable.
There are actually two calls here. The
innermost—<TT
CLASS="LITERAL"
>Jabber.Message()</TT
>—creates a simple
message element that looks like this:</P
><P
><PRE
CLASS="SCREEN"
><message to='[value in cvsuser variable]'>
<subject>CVS Watch Alarm</subject>
<body>[value in message variable]</body>
</message></PRE
></P
><P
>It takes two positional (and required) parameters; any other information
to be passed (such as the <TT
CLASS="LITERAL"
>subject</TT
> in this example)
must be supplied as <I
CLASS="EMPHASIS"
>key=value</I
> pairs.
The outermost—<TT
CLASS="LITERAL"
>con.send()</TT
>— sends whatever
it is given over the XML stream that the <TT
CLASS="LITERAL"
>Jabber.Connection</TT
>
object <TT
CLASS="LITERAL"
>con</TT
> represents. In the case of the
<TT
CLASS="LITERAL"
>Jabber.Message</TT
> call, this is the string representation
of the object so created—i.e. our
<TT
CLASS="LITERAL"
><message/></TT
> element.</P
><P
>Once the notification message has been sent, the script's work is done.
We can therefore disconnect from the server before exiting the script.</P
><P
><PRE
CLASS="SCREEN"
>con.disconnect()</PRE
></P
><P
>Calling the <TT
CLASS="LITERAL"
>disconnect()</TT
> method of the
<TT
CLASS="LITERAL"
>Jabber.Connection</TT
> sends an
<I
CLASS="EMPHASIS"
>unavailable</I
> presence element to the server
on behalf of the user that is connected:</P
><P
><PRE
CLASS="SCREEN"
><presence type='unavailable'/></PRE
></P
><P
>This is sent regardless of whether a
<TT
CLASS="LITERAL"
><presence/></TT
> element was sent during the
conversation, but does no harm if one wasn't.</P
><P
>After sending the unavailable presence information, theXML stream is
closed by sending the stream's closing tag:</P
><P
><PRE
CLASS="SCREEN"
></stream:stream></PRE
></P
><P
>This signifes to the server that the client wishes to end the
conversation. Finally, the socket is closed.</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-7-SECT-1.3.2"
>The script in its entirety</A
></H3
><P
>Here's the script in its entirety.</P
><P
><PRE
CLASS="SCREEN"
>import Jabber, XMLStream
import sys
Server = 'gnu.pipetree.com'
Username = 'cvsmsg'
Password = 'secret'
Resource = 'cvsmsg'
cvsuser = sys.argv[1]
message = ''
for line in sys.stdin.readlines(): message = message + line
con = Jabber.Connection(host=Server)
try:
con.connect()
except XMLStream.error, e:
print "Couldn't connect: %s" % e
sys.exit(0)
con.auth(Username,Password,Resource)
con.send(Jabber.Message(cvsuser, message, subject="CVS Watch Alarm"))
con.disconnect()</PRE
></P
></DIV
></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.AEN6953"
HREF="x6950.htm#AEN6953"
>[1]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>You can find out more about CVS at
<A
HREF="http://www.cvshome.org"
TARGET="_top"
>http://www.cvshome.org</A
>.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN6956"
HREF="x6950.htm#AEN6956"
>[2]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
><A
HREF="http://www.docbook.org"
TARGET="_top"
>http://www.docbook.org</A
>.</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN7118"
HREF="x6950.htm#AEN7118"
>[3]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>http://sourceforge.net/projects/jabberpy/
available at <A
HREF="http://sourceforge.net/projects/jabberpy/"
TARGET="_top"
>http://sourceforge.net/projects/jabberpy/</A
></P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN7180"
HREF="x6950.htm#AEN7180"
>[4]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>This degradation typically will follow the pattern
"<I
CLASS="EMPHASIS"
>zero-knowledge</I
> supported? No.
Ok. How about <I
CLASS="EMPHASIS"
>digest</I
>? No? Ok. Then how about
<I
CLASS="EMPHASIS"
>plaintext</I
>? No? Oh dear. This isn't going to work."</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="c6941.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="x7229.htm"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Messages, Presence, and Presence Subscription</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c6941.htm"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Dialup system watch</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -