]> crepu.dev Git - config.git/blob - djavu-asus/emacs/elpa/jabber-20230715.456/jabber-httpupload.el
Reorganización de directorios
[config.git] / djavu-asus / emacs / elpa / jabber-20230715.456 / jabber-httpupload.el
1 ;;; jabber-httpupload.el --- Emacs Jabber HTTP Upload Implementation -*- lexical-binding: t; -*-
2
3 ;; Copyright 2021 cnngimenez
4 ;;
5 ;; Author: cnngimenez
6 ;; Maintainer: cnngimenez
7 ;; Version: 0.1.0
8 ;; Keywords: comm
9 ;; URL: https://github.com/cnngimenez/emacs-jabber
10 ;; Package-Requires: ((emacs "26.1") (jabber "0.8.92"))
11
12 ;; This program is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation, either version 3 of the License, or
15 ;; (at your option) any later version.
16
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
24
25
26 ;;; Commentary:
27
28 ;; This file implements XEP-0363: HTTP Upload
29 ;; (https://xmpp.org/extensions/xep-0363.html), providing a way to
30 ;; send files (images, audio, etc) through XMPP clients by using
31 ;; server space, and the HTTP protocol to upload and download from it.
32 ;; The advantage is that the sender user does not need to be connected
33 ;; after sharing the file, and the receiver may be disconnected while
34 ;; the sender is uploading.
35
36 ;; The procedure to send a file is as follows -
37
38 ;; 1. Use Disco queries to discover if the server supports the HTTP Upload (~urn:xmpp:http:upload~ namespace).
39 ;; 2. Request a slot to the upload Disco item. The server will answer with a GET and PUT URL.
40 ;; 3. Upload the file to the HTTP server by using the PUT URL.
41 ;; 4. Usually, send the GET URL to the other XMPP clients to allow them to access the uploaded file.
42 ;;
43 ;; TODO -
44 ;; 1. Use wget to send the file
45 ;; 2. Recording audio and sending
46
47 ;;; Code:
48
49 (require 'seq)
50 (require 'fsm)
51 (require 'mailcap)
52 (require 'jabber)
53
54 ;; * Configuration variables *
55
56 (defgroup jabber-httpupload nil "Jabber HTTP Upload Settings."
57 :group 'jabber)
58
59 (defcustom jabber-httpupload-upload-function #'jabber-httpupload-put-file-curl
60 "The function used to upload the file.
61 Some functions calls external programs such as Curl and wget, please check their
62 documentation for more information."
63 :group 'jabber-httpupload
64 :type 'function)
65
66 (defcustom jabber-httpupload-record-command "sox -d -t ogg $(filename).ogg"
67 "What is the command used to record audio?
68 Use $(filename) where the temporal filename should be."
69 :group 'jabber-httpupload
70 :type 'function)
71
72 ;; Disco is used to discover if HTTP Upload is supported on the server
73 ;; side. Two queries are used:
74
75 ;; 1. An IQ Disco items request to get all items supported by the
76 ;; server.
77 ;; 2. For each item, an IQ Disco info request to test if the item is
78 ;; the Upload service.
79
80 ;; The namespace of the HTTP Upload feature is
81 ;; "urn:xmpp:http:upload:0". This will be used on the second query to
82 ;; detect which item is the upload service.
83
84 ;; For more information, see XML examples at the
85 ;; [[https://xmpp.org/extensions/xep-0363.html#disco][Discovering
86 ;; Support section of XEP-0363]].
87
88 ;; This implementation requires an initialization step to fill the
89 ;; `jabber-httpupload-support' variable. This variable registers all
90 ;; connections with their HTTP Upload item. If one of the server
91 ;; associated to a connection does not support HTTP Upload, then it
92 ;; will be registered with a `nil' item.
93
94 ;; * Discovering support *
95
96 (defvar jabber-httpupload-support nil
97 "Alist of Jabber connections and the node with HTTP Upload support.
98 This is filled by the `jabber-httpupload-test-all-connections-suport'.
99 Each element are of the form (jabber-connection . string/nil). If the value is
100 a string, it is the upload item IRI, if nil means no support.")
101
102 (defun jabber-httpupload-test-all-connections-support ()
103 "Test all connections in `jabber-connections' for HTTP Upload support.
104 Store the results at `jabber-httpupload-support'.
105 If the connection is already tested, ignore it."
106 (let ((connections (seq-difference jabber-connections
107 (mapcar #'car jabber-httpupload-support))))
108 (dolist (jc connections)
109 (jabber-httpupload-test-connection-support jc))))
110
111 (defun jabber-httpupload-test-connection-support (jc)
112 "Test if HTTP Upload is supported on the JC connection's server.
113 If it is supported, store the item IRI at `jabber-httpupload-support'.
114
115 This function is asynchronous, thus it won't return any results."
116 (jabber-httpupload-apply-to-items jc
117 (lambda (jc result)
118 (jabber-httpupload-test-item-support jc (elt result 1)))))
119
120 ;; CALLBACK receives three arguments: the jabber connection, extra
121 ;; data and the query result. The result is a list of features
122 ;; supported by the server. For example, if the client receives the
123 ;; following IQ answer:
124 ;;
125 ;; <iq from="upload.server.org"
126 ;; type="result"
127 ;; to="myjid@server.org/pc1"
128 ;; id="emacs-iq-24678.666.622936">
129 ;; <query xmlns="http://jabber.org/protocol/disco#info">
130 ;; <identity name="HTTP File Upload" type="file" category="store"/>
131 ;; <feature var="http://jabber.org/protocol/disco#info"/>
132 ;; <feature var="http://jabber.org/protocol/disco#items"/>
133 ;; <feature var="urn:xmpp:http:upload:0"/>
134 ;; <feature var="urn:xmpp:http:upload"/>
135 ;; <x xmlns="jabber:x:data" type="result">
136 ;; <field type="hidden" var="FORM_TYPE">
137 ;; <value>urn:xmpp:http:upload:0</value>
138 ;; </field>
139 ;; <field type="text-single" var="max-file-size">
140 ;; <value>500000</value>
141 ;; </field>
142 ;; </x>
143 ;; <x xmlns="jabber:x:data" type="result">
144 ;; <field type="hidden" var="FORM_TYPE">
145 ;; <value>urn:xmpp:http:upload</value>
146 ;; </field>
147 ;; <field type="text-single" var="max-file-size">
148 ;; <value>500000</value>
149 ;; </field>
150 ;; </x>
151 ;; </query>
152 ;; </iq>
153 ;;
154 ;; The result would be:
155 ;;
156 ;; ((["HTTP File Upload" "store" "file"])
157 ;; ("http://jabber.org/protocol/disco#info"
158 ;; "http://jabber.org/protocol/disco#items"
159 ;; "urn:xmpp:http:upload:0"
160 ;; "urn:xmpp:http:upload"))
161 ;;
162 ;; This Disco item supports HTTP Upload because the
163 ;; "urn:xmpp:http:upload" namespace is in the second list.
164
165 (defun jabber-httpupload-test-item-support (jc iri)
166 "Test if the IRI Disco item supports HTTP Upload.
167 Get the Disco Info from the provided IRI at the current JC jabber connection,
168 if the HTTP Upload namespace feature is in the answer, store the IRI
169 in `jabber-httpupload-support'."
170 (jabber-disco-get-info jc iri nil
171 (lambda (jc _data result)
172 (when (member "urn:xmpp:http:upload"
173 (nth 1 result))
174 ;; This item supports HTTP Upload... register it!
175 (push (cons jc iri) jabber-httpupload-support)))
176 nil))
177
178 ;; CALLBACK receives three arguments: the jabber connection, extra
179 ;; data and the query result. The result is a list of vector with the
180 ;; node name, its IRI and any other properties.
181 ;;
182 ;; For example, if the client receives the following XML:
183 ;;
184 ;; <iq from="server.org" type="result" to="myjid@server.org/pc1" id="emacs-iq-24677.56646.166389">
185 ;; <query xmlns="http://jabber.org/protocol/disco#items">
186 ;; <item jid="conference.server.org" name="MUC chats!"/>
187 ;; <item jid="upload.server.org"/>
188 ;; </query>
189 ;; </iq>
190 ;;
191 ;; The result would be:
192
193 ;; (["MUC chats!" "conference.server.org" nil] [nil "upload.server.org" nil])
194
195 (defun jabber-httpupload-apply-to-items (jc callback)
196 "Retrieve al Disco IRIs from the server connected in JC.
197 Return a list of IRI strings.
198
199 JC is a jabber connection.
200 CALLBACK is a function that receives two arguments: Jabber connection and
201 the item vector."
202 (let ((node (plist-get (fsm-get-state-data jc) :server)))
203 (jabber-disco-get-items jc node nil
204 (lambda (jc _data result)
205 (dolist (item result)
206 (message "item: %S" item)
207 (funcall callback jc item)))
208 nil)))
209
210 (defun jabber-httpupload-server-has-support (jc)
211 "Check if the server has HTTP Upload support.
212 Return the tuple (jabber-connection . upload-url) when there is support from
213 the server. Return nil when the server does not support HTTP Upload.
214
215 If the server is not in `jabber-httpupload-support', then it is considered as
216 it is not supported. It SHOULD be tested on-line with
217 `jabber-httpupload-test-connection-support' as soon as the connection and
218 authentication is established.
219
220 JC is the Jabber Connection to use."
221
222 (seq-find (lambda (tuple)
223 (and (equal jc (car tuple))
224 (cdr tuple)))
225 jabber-httpupload-support))
226
227 ;; * Requesting a slot *
228
229 ;; The XEP specifies that the client must ask for a "slot" before
230 ;; uploading the file to the server. The slot is a fresh URL that will
231 ;; be enabled for the client to upload the file. The server may give
232 ;; two URLs in one slot query: the uploading URL and the GET URL to
233 ;; share.
234
235 ;; The server may limit the file size to upload.
236
237 ;; <iq from='upload.montague.tld'
238 ;; id='step_03'
239 ;; to='romeo@montague.tld/garden'
240 ;; type='result'>
241 ;; <slot xmlns='urn:xmpp:http:upload:0'>
242 ;; <put url='https://upload.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/tr%C3%A8s%20cool.jpg'>
243 ;; <header name='Authorization'>Basic Base64String==</header>
244 ;; <header name='Cookie'>foo=bar; user=romeo</header>
245 ;; </put>
246 ;; <get url='https://download.montague.tld/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/tr%C3%A8s%20cool.jpg' />
247 ;; </slot>
248 ;; </iq>
249
250 (defun jabber-httpupload-parse-slot-answer (xml-data)
251 "Retrieve the slot data from the XML-DATA information.
252 The XML-DATA is the stanza receive from the Jabber Connection after requesting
253 the slot for a file.
254 The returned list has the PUT URL and the GET URL."
255 (list
256 (jabber-xml-get-attribute (jabber-xml-path xml-data '(slot put)) 'url)
257 (jabber-xml-get-attribute (jabber-xml-path xml-data '(slot get)) 'url)))
258
259 (defun jabber-httpupload--request-slot-successful (jc xml-data data)
260 "Callback function used when the slot request succeeded.
261 XML-DATA is the received XML from the server.
262 DATA is a triple (filedata success-callback success-args) where:
263 FILEDATA is a triple (filename size content-type)
264 SUCCESS-CALLBACK is a function to call after parsing and requesting the
265 upload.
266 It should accept following arguments: JC XML-DATA FILEDATA PUT-GET-URLS
267 and SUCCESS-ARGS.
268 SUCCESS-ARGS is a list to pass to the SUCCESS-CALLBACK."
269 (let ((urls (jabber-httpupload-parse-slot-answer xml-data))
270 (filedata (car data))
271 (success-callback (nth 1 data))
272 (success-args (nth 2 data)))
273 (funcall success-callback jc xml-data filedata urls success-args)))
274
275 ;; Maybe this function should be added as lambda inside the jabber-httpupload-request-slot...
276 (defun jabber-httpupload--request-slot-failed (jc xml-data data)
277 "Callback function used when the slot request failed.
278
279 DATA is a list (filedata error-callback error-args) where:
280 FILEDATA is a triple (filename size content-type)
281 ERROR-CALLBACK is a function to call. If no error-callback is provided, then
282 `error' is used. Its arguments are JC XML-DATA FILEDATA ERROR-ARGS.
283 ERROR-ARGS is list passed to the ERROR-CALLBACK."
284 (let ((filedata (car data))
285 (error-callback (nth 1 data))
286 (error-args (nth 2 data)))
287 (if error-callback
288 (funcall error-callback jc xml-data filedata error-args)
289 (error (format "The file %s cannot be uploaded: SLOT rejected. %S"
290 (car data) xml-data)))))
291
292 ;; The XML used to request a slot is similar to the following -
293 ;; <iq from='romeo@montague.tld/garden'
294 ;; id='step_03'
295 ;; to='upload.montague.tld'
296 ;; type='get'>
297 ;; <request xmlns='urn:xmpp:http:upload:0'
298 ;; filename='très cool.jpg'
299 ;; size='23456'
300 ;; content-type='image/jpeg' />
301 ;; </iq>
302
303 (defun jabber-httpupload-request-slot (jc filedata success-callback success-args
304 &optional error-callback error-args)
305 "Request a slot for HTTP Upload to the server's connection.
306 JC is an active Jabber Connection.
307 FILEDATA is a list with (filename size content-type).
308 SUCCESS-CALLBACK is a function name to call when the slot is received. Its
309 arguments should be: jc xml-data data and put-get-URLs.
310 SUCCESS-ARGS is a list of arguments used by the SUCCESS-CALLBACK
311 ERROR-CALLBACK is a function to call on failure. Its arguments should be:
312 jc xml-data.
313 ERROR-ARGS is a list with arguments for ERROR-CALLBACK."
314 (let ((filename (file-name-nondirectory (car filedata)))
315 (size (nth 1 filedata))
316 (content-type (nth 2 filedata)))
317 (jabber-send-iq jc (cdr (jabber-httpupload-server-has-support jc)) "get"
318 `(request ((xmlns . "urn:xmpp:http:upload:0")
319 (filename . ,filename)
320 (size . ,size)
321 (content-type . ,content-type)))
322 #'jabber-httpupload--request-slot-successful
323 (list filedata success-callback success-args)
324 #'jabber-httpupload--request-slot-failed
325 (list filedata error-callback error-args))))
326
327 ;; * Uploading the file *
328
329 ;; Use the HTTP protocol to upload the file to the PUT URL provided by
330 ;; the slot.
331
332 ;; The following functions call the upload programs asynchronously.
333 ;; When the program ends, a callback function is called with one
334 ;; argument provided by the caller function.
335
336 ;; The uploading process supports multiple calls. For example, the
337 ;; user may call `jabber-httpupload-send-file' again while the upload process of a
338 ;; previous `jabber-httpupload-send-file' call is still running.
339
340 ;; Also, a callback can be provided in order to send the URL to the
341 ;; receiving Jabber client or to perform any other action after
342 ;; uploading the file.
343
344 (defun jabber-httpupload-ignore-certificate (jc)
345 "Should the SSL/TLS certificates be ignore from JC connection?
346 Check if JC URL is in the variable `jabber-invalid-certificate-servers', if it
347 is the XMPP and HTTPs connection should be established regarding their
348 certificate validation status."
349 (member (plist-get (fsm-get-state-data jc) :server)
350 jabber-invalid-certificate-servers))
351
352 (defun jabber-httpupload-upload-file (filepath content-type put-url
353 callback callback-arg
354 &optional ignore-cert-problems)
355 "Update the given file at FILEPATH to the provided PUT-URL.
356 The CONTENT-TYPE (MIME type) of the file must match the one provided
357 to the Jabber Connection with `jabber-httpupload-request-slot'.
358 IGNORE-CERT-PROBLEMS allows to connect with HTTPS servers with invalid or
359 non-trusted SSL/TLS certificates.
360 When the process ends, a callback function is called using the following
361 code: (funcall CALLBACK CALLBACK-ARG)"
362 (unless (funcall jabber-httpupload-upload-function filepath content-type put-url
363 callback callback-arg
364 ignore-cert-problems)
365 (error (concat "The upload function failed to PUT the file to the server. "
366 "Try other function or install the required program"))))
367
368 ;; Multiple files can be uploaded in parallel, and thus multiple
369 ;; subprocess could be working at the same time. This happens when the
370 ;; user calls interactively `jabber-httpupload-send-file' twice or while a file is
371 ;; still uploading.
372
373 ;; This variable keeps track of the subprocesses and their callback
374 ;; along with any data required by these functions.
375
376 (defvar jabber-httpupload-upload-processes nil
377 "Alist of running processes uploading the file to the server.
378 List of running processes uploading the file to the server
379 associated with their callback and arguments. Each element has
380 the following format: (process . (callback arg))")
381
382 ;; When the file has been uploaded, the process is still registered
383 ;; with its callback function. This callback should be called and the
384 ;; process deleted from the system.
385
386 (defun jabber-httpupload-process-ended (process)
387 "What to do when an upload process ends.
388 PROCESS is the process that ended.
389 First remove the process from `jabber-httpupload-upload-processes',
390 then call its callback with the provided argument."
391 (let* ((data (assq process jabber-httpupload-upload-processes))
392 (callback (cadr data))
393 (callback-arg (caddr data)))
394 (setq jabber-httpupload-upload-processes
395 (assq-delete-all process jabber-httpupload-upload-processes))
396 (funcall callback callback-arg)))
397
398 ;; Using CURL to send the file
399
400 ;; These functions call curl to send the file to the server. A
401 ;; sentinel is required to check when the subprocess finishes to call
402 ;; the next function (usually, send the URL to the other jabber
403 ;; client).
404
405 (defun jabber-httpupload-curl-sentinel (process event)
406 "Detect when Curl ends and act accordingly.
407 PROCESS is the asynchronous Curl call.
408 EVENT is a string describing the reason the sentinel were called.
409
410 When EVENT is \"finished\n\", then the function
411 `jabber-httpupload-process-ended' is called."
412 (with-current-buffer (process-buffer process)
413 (let ((inhibit-read-only t))
414 (goto-char (point-max))
415 (insert (format "Sentinel: %S event received." event))))
416 (when (string= event "finished\n")
417 (jabber-httpupload-process-ended process)))
418
419 ;; This is the function used to send a file to the server by running a curl subprocess.
420 (defun jabber-httpupload-put-file-curl (filepath content-type put-url
421 callback callback-arg
422 &optional ignore-cert-problems)
423 "Use the curl command to put the file at FILEPATH into the PUT-URL.
424 Send the SIZE and CONTENT-TYPE MIME as headers.
425 IGNORE-CERT-PROBLEMS enable the use of HTTPS connections with invalid or
426 non-trusted SSL/TLS certificates. If nil, curl will validate the certificate
427 provided by the HTTP/S Web server.
428 When the process ends, the function CALLBACK is called like the following
429 call: (funcall CALLBACK CALLBACK-ARG).
430 The process is registered at `jabber-httpupload-upload-processes' AList with
431 the provided CALLBACK and CALLBACK-ARG."
432 (let* ((exec-path (executable-find "curl"))
433 (cmd (format "%s %s --upload-file '%s' -H \"content-type: %s\" '%s'"
434 exec-path
435 (if ignore-cert-problems
436 "--insecure"
437 "")
438 filepath content-type put-url)))
439 (when exec-path
440 (with-current-buffer (get-buffer-create "*jabber-httpupload-put-file-curl*")
441 (let ((inhibit-read-only t))
442 (goto-char (point-max))
443 (insert (format "%s Uploading to %s with curl:\n$ %s"
444 (current-time-string)
445 put-url
446 cmd))
447 (let ((process (start-process-shell-command "jabber-httpupload-put-file-curl"
448 (current-buffer)
449 cmd)))
450 (push (cons process (list callback callback-arg))
451 jabber-httpupload-upload-processes)
452 (set-process-sentinel process #'jabber-httpupload-curl-sentinel))
453 (insert "-- done --")
454 t)))))
455
456 ;; * Send the file URL to the client *
457
458 ;; The following message is similar to one sent by Conversations -
459 ;;
460 ;; <message from="from_jid@fromserver.org/Resource"
461 ;; id="fc824dcb-c654-4911-a22b-25718dfe4590"
462 ;; type="chat"
463 ;; to="to_jid@toserver.org">
464 ;; <body>https://fromserver.org:5281/upload/kFTT5ET9JeF_CC6s/_IJNy8ZUSRGiKyVxjf5FkA.jpg</body>
465 ;; <request xmlns="urn:xmpp:receipts"/>
466 ;; <markable xmlns="urn:xmpp:chat-markers:0"/>
467 ;; <origin-id id="fc824dcb-c654-4911-a22b-25718dfe4590" xmlns="urn:xmpp:sid:0"/>
468 ;; <x xmlns="jabber:x:oob">
469 ;; <url>https://fromserver.org:5281/upload/kFTT5ET9JeF_CC6s/_IJNy8ZUSRGiKyVxjf5FkA.jpg</url>
470 ;; </x>
471 ;; <stanza-id xmlns="urn:xmpp:sid:0"
472 ;; id="7e18d73a-278c-4e5e-bd09-61c12187e5d6"
473 ;; by="to_jid@toserver.org"/>
474 ;; </message>
475
476 ;; The message should add the "body" and "x" tags.
477
478 (defun jabber-httpupload-send-file-url (jc jid get-url)
479 "Send the GET URL address to the JID user.
480 The message requiers the GET-URL of the slot file, the receiver's JID
481 and the JC Jabber Connection."
482 ;; This could be a possibliity, but... cannot send the x tag.
483 ;; (jabber-send-message jc jid nil get-url nil)
484 (let ((fromjid (jabber-connection-original-jid jc))
485 (type (if (assoc jid *jabber-active-groupchats*)
486 "groupchat"
487 "chat")))
488 (jabber-send-sexp jc
489 `(message ((to . ,jid)
490 (from . ,fromjid)
491 (type . ,type))
492 (body () ,get-url)
493 (x ((xmlns . "jabber:x:oob"))
494 (url () ,get-url))))))
495
496 ;; * Chat buffer *
497
498 ;; ** Send file (complete process) **
499
500 ;; The following functions add interactive commands to the chat buffer
501 ;; to send the GET URL to the current (or selected) client.
502
503 (defun jabber-httpupload-send-file (jc jid filepath)
504 "Send the file at FILEPATH to the user JID.
505 JC is the Jabber Connection to send the file URL."
506 (interactive (list (jabber-read-account)
507 (jabber-read-jid-completing "Send file to: " nil nil nil 'full t)
508 (read-file-name "File to send:")))
509 (unless (jabber-httpupload-server-has-support jc)
510 (error "The Jabber Connection provided has no HTTP Upload support"))
511 (let* ((size (file-attribute-size (file-attributes filepath)))
512 (content-type (mailcap-extension-to-mime (file-name-extension filepath)))
513 (filedata (list filepath size content-type)))
514 (jabber-httpupload-request-slot jc filedata
515 #'jabber-httpupload--slot-reserved
516 (list jid))))
517
518 ;; The following functions are callbacks used in the following order:
519
520 ;; 1. `jabber-httpupload-request-slot' calls `jabber-httpupload--slot-reserved'.
521 ;; 2. `jabber-httpupload--slot-reserved' calls `jabber-httpupload--upload-done'.
522 ;; 3. `jabber-httpupload--upload-done' calls `jabber-httpupload-send-file-url'.
523
524 ;; This form of calling is required because of the asynchronous
525 ;; behaviour of the upload file function.
526
527 (defun jabber-httpupload--upload-done (data)
528 "Callback function used when the upload is done.
529 When the upload process finished, a callback function is called with an
530 argument.
531 This function is expected to be used as the CALLBACK argument for the function
532 `jabber-httpupload-upload-file', DATA is its CALLBACK-ARG argument.
533 Also, see `jabber-httpupload-process-ended' for more information.
534 DATA is expected to have the following foramt: (jc jid get-url).
535 After the upload is done, send the get-url to the destined Jabber user JID."
536 (let ((jc (car data))
537 (jid (nth 1 data))
538 (get-url (nth 2 data)))
539 (condition-case err
540 (jabber-httpupload-send-file-url jc jid get-url)
541 (error "Cannot send message. Error: %S" err))))
542
543 ;; When the slot is reserved, the HTTP upload should be started.
544 (defun jabber-httpupload--slot-reserved (jc _xml-data filedata urls extra-data)
545 "Callback function used when the slot request succeeded.
546 JC is the current Jabber Connection.
547 XML-DATA is the received XML from the server.
548 FILEDATA is a triple `(filepath size content-type).
549 URLS is a tuple `(put-url get-url).
550 EXTRA-DATA is a list `(jid)"
551 (let ((filepath (car filedata))
552 (content-type (nth 2 filedata))
553 (jid (car extra-data))
554 (get-url (cadr urls))
555 (put-url (car urls)))
556 (message "jabber-httpupload: slot PUT and GET URLs: %S" urls)
557 (condition-case err
558 (jabber-httpupload-upload-file (expand-file-name filepath)
559 content-type
560 put-url
561 #'jabber-httpupload--upload-done (list jc jid get-url)
562 (jabber-httpupload-ignore-certificate jc))
563 (error "Cannot upload the file. Error: %S" err))))
564
565 ;; ** TODO Recording and sending audio **
566
567 ;; TODO
568 (defun jabber-httpupload--record-audio ()
569 "Create a new audio record and save the file into a temporal directory."
570 (let ((process (start-process-shell-command
571 "jabber-httpupload-record-audio"
572 (current-buffer)
573 (replace-string "$(filename"
574 "/tmp/jabber-httpupload-record"
575 jabber-httpupload-record-command))))
576 (set-process-sentinel process #'jabber-httpupload-record-sentinel)))
577
578 ;; * Add hooks *
579 ;; Some function should start automatically.
580
581 ;; ** Test connection support after session is established **
582 ;; Call `jabber-httpupload-test-connection-support' as soon as
583
584 ;; * Adding functions to hooks *
585 ;; ** Test HTTP Upload support after connecting **
586 (add-hook 'jabber-post-connect-hooks #'jabber-httpupload-test-connection-support)
587
588 (provide 'jabber-httpupload)
589
590 ;;; jabber-httpupload.el ends here