2007年10月 存档

XMPP/Jabber/GTalk协议概览

2007年10月31日,星期三

万圣节前夜,嘎嘎,写一篇XMPP的文章,主要来自Jabber官方的Technical Overview

Overview

XMPPJabber软件基金会开发,最早在Jabber上实现。Jabber项目由Jeremie Miller在1998年开始的一个免费、开源的项目,用于提供给MSN、Yahoo!的IM服务。由于XMPP是一种基于XML架构的开放式协议,在IM通讯中被广泛采用,已经得到了互联网工程任务组(IETF)的批准(RFC 3920|RFC 3921)。

IQ

即Information Query,是XMPP协议中一个类似HTTP的GET、POST的动词。比如说修改Jabber密码:

<iq type='set' to='jabber.org'>
<query xmlns='jabber:iq:register'>
<username>username</username>
<password>newpassword</password>
</query>
</iq>

JID

即Jabber ID,格式为:
[node@]domain[/resource]
node是用户名,domain是域;如果是Google Talk的话域就是 gmail.com;resource表示工作状态,Jabber允许在不同的地方同时登陆一个Jabber账号,用resource来表示不同的状态,可以自定义,GTalk目前版本定义的resource就是 Talk.v104C0F37955
例如:estbot@googlemail.com/AtWork

Disco

Service Discovery,一个Jabber服务器可能不止提供了IM服务,还提供了和其它IM互通网关、群聊等特性。

Stanza

一个XML片段

Roster

联系人名单

Presence

即隐身功能,把你的在线/离线状态只告诉一部分联系人

Subscription

订阅一个联系人的在线状态,通俗的讲就是添加好友。A给服务器发送一个presence消息,要subscribe B,那么相当于A要添加B为好友。

show

忙碌状态
away――在线,但不能马上联系上
chat――在线并有兴趣聊天
dnd――在线,但不想被打扰(“dnd”表示“do not disturb”)
xa――在线,但已经离开很长时间了(“xa”表示“extended away”)
GTalk里,绿色图标表示<show />,没有任何show的值,如果是红色图标则是<show>dnd</show>,只有这两种状态

status

好友的个性签名。好友的头像是通过X标签来获得的

vCard

联系人名片,见 RFC 2426

Jingle

Google定义的Jabber扩展,包含了p2p、语聊、文件传输、穿防火墙/NAT/Proxy等高级功能。例如File Transfer模块
libjingle file transfer

剩下的想起来了再添加,看RFC真是一件超级麻烦的事情,CSDN上还有Jabber协议的中文版本 :-)

[PyXMPP]echobot.py that works with GTalk

2007年10月30日,星期二

I am transferring my GTalkBot From XMPPPy to PyXMPP, but PyXMPP's echobot.py example does not work with Google Talk, I tried Mikal's patch and got it work!

Here is the patched source for echobot.py

#!/usr/bin/python -u
#
# This example is a simple "echo" bot
#
# After connecting to a jabber server it will echo messages, and accept any
# presence subscriptions. This bot has basic Disco support (implemented in
# pyxmpp.jabber.client.Client class) and jabber:iq:vesion.


import sys import logging import locale import codecs


From pyxmpp.all import JID,Iq,Presence,Message,StreamError From pyxmpp.jabber.client import JabberClient From pyxmpp import streamtls


class Client(JabberClient): """Simple bot (client) example. Uses `pyxmpp.jabber.client.JabberClient` class as base. That class provides basic stream setup (including authentication) and Service Discovery server. It also does server address and port discovery based on the JID provided."""


def __init__(self, jid, password):


# if bare JID is provided add a resource -- it is required if not jid.resource: jid=JID(jid.node, jid.domain, "Echobot")


# setup client with provided connection information # and identity data tls = streamtls.TLSSettings(require=True, verify_peer=False) auth = [ 'sasl :P LAIN' ]


JabberClient.__init__(self, jid, password, disco_name="PyXMPP example: echo bot", disco_type="bot", tls_settings=tls, auth_methods=auth)


# disco_name="PyXMPP example: echo bot", disco_type="bot")


# register features to be announced via Service Discovery self.disco_info.add_feature("jabber:iq:version")


def stream_state_changed(self,state,arg): """This one is called when the state of stream connecting the component to a server changes. This will usually be used to let the user know what is going on.""" print "*** State changed: %s %r ***" % (state,arg)


def session_started(self): """This is called when the IM session is successfully started (after all the neccessery negotiations, authentication and authorizasion). That is the best place to setup various handlers for the stream. Do not forget about calling the session_started() method of the base class!""" JabberClient.session_started(self)


# set up handlers for supported queries self.stream.set_iq_get_handler("query","jabber:iq:version",self.get_version)


# set up handlers for stanzas self.stream.set_presence_handler("available",self.presence) self.stream.set_presence_handler("subscribe",self.presence_control) self.stream.set_presence_handler("subscribed",self.presence_control) self.stream.set_presence_handler("unsubscribe",self.presence_control) self.stream.set_presence_handler("unsubscribed",self.presence_control)


# set up handler for self.stream.set_message_handler("normal",self.message)


def get_version(self,iq): """Handler for jabber:iq:version queries.


jabber:iq:version queries are not supported directly by PyXMPP, so the XML node is accessed directly through the libxml2 API. This should be used very carefully!""" iq=iq.make_result_response() q=iq.new_query("jabber:iq:version") q.newTextChild(q.ns(),"name","Echo component") q.newTextChild(q.ns(),"version","1.0") self.stream.send(iq) return True


def message(self,stanza): """Message handler for the component.


Echoes the message back if its type is not 'error' or 'headline', also sets own presence status to the message body. Please note that all message types but 'error' will be passed to the handler for 'normal' message unless some dedicated handler process them.


:returns: `True` to indicate, that the stanza should not be processed any further.""" subject=stanza.get_subject() body=stanza.get_body() t=stanza.get_type() print u'Message From %s received.' % (unicode(stanza.get_from(),)), if subject: print u'Subject: "%s".' % (subject,), if body: print u'Body: "%s".' % (body,), if t: print u'Type: "%s".' % (t,) else: print u'Type: "normal".' % (t,) if stanza.get_type()=="headline": # 'headline' messages should never be replied to return True if subject: subject=u"Re: "+subject m=Message( to_jid=stanza.get_from(), from_jid=stanza.get_to(), stanza_type=stanza.get_type(), subject=subject, body=body) self.stream.send(m) if body: p=Presence(status=body) self.stream.send(p) return True


def presence(self,stanza): """Handle 'available' (without 'type') and 'unavailable' .""" msg=u"%s has become " % (stanza.get_from()) t=stanza.get_type() if t=="unavailable": msg+=u"unavailable" else: msg+=u"available"


show=stanza.get_show() if show: msg+=u"(%s)" % (show,)


status=stanza.get_status() if status: msg+=u": "+status print msg


def presence_control(self,stanza): """Handle subscription control stanzas -- acknowledge them.""" msg=unicode(stanza.get_from()) t=stanza.get_type() if t=="subscribe": msg+=u" has requested presence subscription." elif t=="subscribed": msg+=u" has accepted our presence subscription request." elif t=="unsubscribe": msg+=u" has canceled his subscription of our." elif t=="unsubscribed": msg+=u" has canceled our subscription of his presence."


print msg p=stanza.make_accept_response() self.stream.send(p) return True


def print_roster_item(self,item): if item.name: name=item.name else: name=u"" print (u'%s "%s" subscription=%s groups=%s' % (unicode(item.jid), name, item.subscription, u",".join(item.groups)) )


def roster_updated(self,item=None): if not item: print u"My roster:" for item in self.roster.get_items(): self.print_roster_item(item) return print u"Roster item updated:" self.print_roster_item(item)


# XMPP protocol is Unicode-based to properly display data received # _must_ convert it to local encoding or UnicodeException may be raised locale.setlocale(locale.LC_CTYPE,"") encoding=locale.getlocale()[1] if not encoding: encoding="us-ascii" sys.stdout=codecs.getwriter(encoding)(sys.stdout,errors="replace") sys.stderr=codecs.getwriter(encoding)(sys.stderr,errors="replace")


# PyXMPP uses `logging` module for its debug output # applications should set it up as needed logger=logging.getLogger() logger.addHandler(logging.StreamHandler()) logger.setLevel(logging.INFO) # change to DEBUG for higher verbosity


if len(sys.argv)<3: print u"Usage:" print "\t%s JID password" % (sys.argv[0],) print "example:" print "\t%s test@localhost verysecret" % (sys.argv[0],) sys.exit(1) print u"creating client..." c=Client(JID(sys.argv[1]),sys.argv[2]) print u"connecting..." c.connect() print u"looping..." try: # Component class provides basic "main loop" for the applitation # Though, most applications would need to have their own loop and call # component.stream.loop_iter() From it whenever an event on # component.stream.fileno() occurs. c.loop(1) except KeyboardInterrupt: print u"disconnecting..." c.disconnect() print u"exiting..."

标准Python模板

2007年10月29日,星期一

每次新建一个python都要写coding:utf-8之类的,麻烦。干脆修改注册表,添加一个模板

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.py\ShellNew]
"FileName"="E:\\Python\\install\\模板.py"

E:\Python\install\模板.py 内容为:
[code:python]
#!/usr/bin/env python
#coding:utf-8

def main():
#Add your code here

if "__main__" == __name__:
main()
[/code]

这样每次可以直接在资源管理器里 右键 -> 新建 -> Python File

动态调用Python脚本

2007年10月29日,星期一

想实现类似django那样的modify while debugging功能,应该是reload()函数做的

[code:python]
#!/usr/bin/env python
#coding:utf-8

import time, settings

while 1:
reload(settings)
print settings.settings1
time.sleep(0.2)
[/code]

配置文件 settings.py:
[code:python]
#!/usr/bin/env python
#coding:utf-8

settings1 = "variable1"
[/code]

在命令行运行主脚本,然后用记事本修改settings.py的变量,可以看到变量值被即时更新了。

[JScript]批量导出Kerio Mail的帐号

2007年10月28日,星期日

最近忙着网管会的邮件服务从Kerio Mail Server转移到Google Apps以体验谷歌企业套件的强大协作功能,遇到一个小问题就是大量的Email帐号需要批量导入Google Apps,于是写了一个JS脚本来完成这个工作。

使用方法:找到Kerio Mail Server的安装目录,把users.cfg复制出来,然后把下列代码保存为export.js放置到users.cfg同一个目录下。运行export.js即可。

[code:javascript]
/*****************************************************************************
Export Kerio Mail Server users to CSV file, version 1.2, 2007-10-28
Written by est, electronicstar@126.com, http://initiative.yo2.cn/
/****************************************************************************/

//Default password for each account
DEFAULT_PASSWORD = default
OUTPUT_FILE = 'out.csv'

var xmlDoc = new ActiveXObject("Msxml2.DOMDocument")
xmlDoc.async = false
//You should locate users.cfg file, which is always in Kerio Mail installation directory
xmlDoc.load("users.cfg")

var users = xmlDoc.selectNodes("//config/list/listitem/variable[@name='Name']")
var names = xmlDoc.selectNodes("//config/list/listitem/variable[@name='Fullname']")

str='"username","first name","last name","password"\n'
for(i=0;ixmlDoc对象和XPath(教程),呵呵。

Vista:调整分区大小中途断电……

2007年10月28日,星期日

今天为了安装Leopard,把硬盘上的UbuntuStudio分区删除了,腾出来6GB,还得腾出6GB,于是把E:盘上的0Cisco Document DVD 2007删除了,然后在Vista的 磁盘管理 里调整空闲分区大小。

令人气愤的是,Vista使我的硬盘狂转了30多分钟,没有任何提示,于是我打算重启计算机,但是关机就关了10多分钟,实在不行了,断电

后果是可怕的,GRUB提示22错误,看来是找不到MBR了,用启动盘启动Diskgen重建分区表,顺利引导Vista,可惜系统提示0x00000000错误,看来已经损坏了……

我安装的是RTM的Vista,但是安装盘找不到了,找到一个RC1的Vista,修复,重启,顺利启动~~~看了下后果不是很严重,C:盘和E:盘盘符丢失,D:和E:盘符颠倒,令人惊奇的是,没有任何数据丢失!

用开机引导的磁盘检查仔细看过了C:、D:和E:盘,no errors found!

看来Vista的数据管理真的很优秀,在这么极端的环境下还能够保证磁盘数据的完整性。这也是令我坚持使用Vista的理由吧。

以后不敢再做这样危险的操作了。

Google Experimental的新功能:电影搜索

2007年10月27日,星期六

今天看完了《生化危机3:灭绝 Resident Evil- Extinction (2007)》,去Google了一下相关信息,惊喜的发现一个新功能:
12.jpg
输入一个美国城市的名字,比如说NewYork,可以得到当地影院的播出时间,我们还能立即得到这部影片是R级的(Restricted)
21.jpg
如果点击了 保存位置Remember this location 那么第二次搜索Resident Evil关键字的时候就会直接列出电影院的播出时间、甚至Google Maps的链接。
3.jpg
还有IMDb的链接,爽~

看来,Google真的要做到,One search engine to them all!

附注:要体验该功能需要加入Google Experimental测试计划

SUN of bitch - why Java sucks

2007年10月27日,星期六

SUN公司真操蛋。

今天在TopCoder做题,需要JRE1.4.2环境,哼哼,Java在我的映像中一直是低效和臃肿的代名词,但是为了……免费的牛奶、面包还有Topcoder的T-Shirt,所以还是忍了。于是去SUN官网下载Java Runtime Environment。但是下载JRE需要去下载SUN公司的专用下载器Sun Download Manager,比较瓜的是,SUN公司推荐用SDM来下载SDM,真TMD的SB;比较气愤的是,SDM的安装程序还用UPX加壳,还不能直接解压
。好啦,安装好了SDM,终于可以下载了,哼,貌似192开头的IP很牛X似的。最终得到JRE的下载地址:

http://192.18.108.229/ECom/EComTicketServlet/BEGINCC6D7D4E58DC482AC4ED0B01ED34B2B9/-2147483648/2425957131/1/851618/851546/2425957131/2ts+/westCoastFSEND/j2re-1.4.2_16-oth-JPR/j2re-1.4.2_16-oth-JPR:3/j2re-1_4_2_16-windows-i586-p.exe

最后发现,最BT的是,SDM是用Java写的 -_-! !@#¥%……&×()

Hardest Chinese Ever 最复杂的汉字

2007年10月26日,星期五

国外有个网站在投票选举最复杂的汉字,觉得非常有趣

Exorcism
咒语“驅魔”
noodle
面条?
one
异体字“一”
cheat
据说是“作弊”的意思
flying squirrel
蝙蝠,看一个“鸟”在田里飞呢

这里我也写几个能够打出来的字,看看有谁认识不?



顺便贴一个“中▁华▁民▁国▁教育部诡异字字典”的网址,可以根据字形来查字,哈哈

http://140.111.1.40/main.htm

index.dat

2007年10月25日,星期四

查了下,Vista下的index.dat文件有24处之多,真是BT,看来隐私漏了不少。
dir /a /b /s index.dat
得到结果:
C:\Users\est\AppData\Local\Microsoft\Feeds Cache\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007100120071008\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007100820071015\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007101220071013\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007101520071022\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007102220071023\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007102320071024\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007102420071025\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007102520071026\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\History\Low\History.IE5\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\index.dat
C:\Users\est\AppData\Local\Microsoft\Windows\Temporary Internet Files\Low\Content.IE5\index.dat
C:\Users\est\AppData\Roaming\Adobe\FileBrowser\Photoshop7\index.dat
C:\Users\est\AppData\Roaming\Microsoft\Internet Explorer\UserData\index.dat
C:\Users\est\AppData\Roaming\Microsoft\Office\Recent\index.dat
C:\Users\est\AppData\Roaming\Microsoft\Windows\Cookies\index.dat
C:\Users\est\AppData\Roaming\Microsoft\Windows\Cookies\Low\index.dat

C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Feeds Cache\index.dat
C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\History\History.IE5\index.dat
C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007040620070407\index.dat
C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\History\History.IE5\MSHist012007091020070911\index.dat
C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\index.dat
C:\Windows\System32\config\systemprofile\AppData\Roaming\Microsoft\Windows\Cookies\index.dat

过几天争取看看reverse engineering index.dat files,还有IE缓存记录

Vista下找到cookie的路径不容易啊,Win+R运行cookies,提示

[Window Title]
位置不可用
[Content]
无法访问 C:\Users\est\Cookies。
拒绝访问。
[确定]

经几个朋友讨论,发现了进入cookie文件夹的快捷方式:Win+R运行 shell:cookies ,最终路径是 C:\Users\est\AppData\Roaming\Microsoft\Windows\Cookies

不看不知道,一看吓一跳,最终结果是,3933个项目 2.10MB,暴汗。