{"id":751,"date":"2013-08-18T08:04:11","date_gmt":"2013-08-18T15:04:11","guid":{"rendered":"http:\/\/www.dreness.com\/blog\/?p=751"},"modified":"2019-12-07T17:10:30","modified_gmt":"2019-12-08T00:10:30","slug":"si-file-transfer-entity-capabilities-ichat-and-your-jabber-bot","status":"publish","type":"post","link":"https:\/\/dreness.com\/blog\/archives\/751","title":{"rendered":"SI File Transfer, Entity Capabilities, iChat, and Your Jabber Bot"},"content":{"rendered":"<p>What do these things have in common? This is the only place on the entire internet where you can read useful information about all of these things.<\/p>\n<p>I&#8217;ve toyed with jabber bots before, mostly using the various XMPP stacks available for Python. This time, I wanted to find something even more high level, and I think I found it in\u00a0<a title=\"Blather, a super sweet, very high level XMPP bot\" href=\"https:\/\/github.com\/adhearsion\/blather\" target=\"_blank\" rel=\"noopener noreferrer\">Blather<\/a>\u00a0&#8211; the example echo bot weighs in at 9 lines of code, including the 2 require statements. Trying to send it a file, however, results in this:<\/p>\n<p><a href=\"https:\/\/dreness.com\/blog\/wp-content\/uploads\/2013\/08\/unable-to-receive.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-752\" alt=\"unable-to-receive\" src=\"https:\/\/dreness.com\/blog\/wp-content\/uploads\/2013\/08\/unable-to-receive.png\" width=\"830\" height=\"260\" srcset=\"https:\/\/dreness.com\/blog\/wp-content\/uploads\/2013\/08\/unable-to-receive.png 830w, https:\/\/dreness.com\/blog\/wp-content\/uploads\/2013\/08\/unable-to-receive-300x93.png 300w\" sizes=\"auto, (max-width: 830px) 100vw, 830px\" \/><\/a><\/p>\n<p>I spent a while figuring out what&#8217;s required of a jabber bot so that <del>iChat\u00a0<\/del>Messages will allow its user to send a file. Researching XMPP file transfer might not be such a mystical odyssey if you were implementing everything from scratch, but if instead you&#8217;re trying to (ostensibly) save some time and write as little code as possible, the path isn&#8217;t terribly clear. In this case, I ended up learning a fair amount about XMPP. ~20 hours of fervent web searching and reading yielded ~3 lines of code.<\/p>\n<p>I found one solitary <a href=\"https:\/\/groups.google.com\/forum\/#!msg\/xmpp-blather\/bsP_JVqj6YY\/tnENQD7BC60J\" target=\"_blank\" rel=\"noopener noreferrer\">post<\/a>\u00a0from somebody writing a Blather bot who had this same problem. He was informed that the bot needs to <a href=\"https:\/\/xmpp.org\/extensions\/xep-0030.html#info\" target=\"_blank\" rel=\"noopener noreferrer\">advertise<\/a> the correct set of <a href=\"https:\/\/xmpp.org\/extensions\/attic\/xep-0115-1.3.html\" target=\"_blank\" rel=\"noopener noreferrer\">capabilities<\/a>\u00a0for <a href=\"https:\/\/xmpp.org\/extensions\/xep-0096.html\" target=\"_blank\" rel=\"noopener noreferrer\">file transfer<\/a>, however that guy wasn&#8217;t sure what they were. Somebody else <a href=\"https:\/\/groups.google.com\/forum\/\" target=\"_blank\" rel=\"noopener noreferrer\">chimed in<\/a>, but that <a href=\"https:\/\/gist.github.com\/benlangfeld\/1016487\" target=\"_blank\" rel=\"noopener noreferrer\">response<\/a> was broken and also incomplete &#8211; but it was enough to put me on the right track. The minimum set of capabilities needed to be a XEP-0096 compliant file transfer recipient \u00a0are:<\/p>\n<pre>\u00a0 \u00a0\u00a0&lt;feature var=\"http:\/\/jabber.org\/protocol\/ibb\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/bytestreams\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/si\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/si\/profile\/file-transfer\"\/&gt;<\/pre>\n<p><a href=\"https:\/\/gist.github.com\/dreness\/6261903#file-filesink-rb\" target=\"_blank\" rel=\"noopener noreferrer\"> Here<\/a>\u00a0is a working XMPP bot that can receive files sent by another client, using the XEP 0096 spec. Running it looks something like this:<\/p>\n<pre>csbot@botboy[~\/cs-bot]ruby xmpp_receiver.rb\r\nConnected to talkman@talk.example.com\/1376830693085. Sent capabilities:\r\n&lt;iq type=\"result\" id=\"blather0001\"&gt;\r\n\u00a0 &lt;query xmlns=\"http:\/\/jabber.org\/protocol\/disco#info\" node=\"http:\/\/dreness.com\/csbot#cc5+HwPwVxjmjK9bPjmuvv\/Ehh8=\"&gt;\r\n\u00a0 \u00a0 &lt;identity name=\"csbot\" type=\"bot\" category=\"client\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/ibb\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/bytestreams\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/si\"\/&gt;\r\n\u00a0 \u00a0 &lt;feature var=\"http:\/\/jabber.org\/protocol\/si\/profile\/file-transfer\"\/&gt;\r\n\u00a0 &lt;\/query&gt;\r\n&lt;\/iq&gt;\r\n\r\nReceiving file from dre@xomg.example.com\/foci\r\n&lt;file xmlns=\"http:\/\/jabber.org\/protocol\/si\/profile\/file-transfer\"\r\n  xmlns:ichat=\"apple:profile:transfer-extensions\"\r\n  <span style=\"color: #222222; font-family: 'Courier 10 Pitch', Courier, monospace; line-height: 21px;\">name=\"btc-watcher.py\"\r\n  size=\"5387\"\r\n  posixflags=\"000001ED\"\/&gt;<\/span><\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What do these things have in common? This is the only place on the entire internet where you can read useful information about all of these things. I&#8217;ve toyed with jabber bots before, mostly using the various XMPP stacks available &hellip; <a href=\"https:\/\/dreness.com\/blog\/archives\/751\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-751","post","type-post","status-publish","format-standard","hentry","category-bitbucket"],"_links":{"self":[{"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/posts\/751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/comments?post=751"}],"version-history":[{"count":14,"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/posts\/751\/revisions"}],"predecessor-version":[{"id":1240,"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/posts\/751\/revisions\/1240"}],"wp:attachment":[{"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/media?parent=751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/categories?post=751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dreness.com\/blog\/wp-json\/wp\/v2\/tags?post=751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}