1 ;;; emchat-v8.el --- ICQ v8 for emchat.
3 ;; Copyright (C) 2004 - 2008 Steve Youngs, Zajcev Evgeny
5 ;; Author: Zajcev Evgeny <zevlg@yandex.ru>
6 ;; Maintainer: Steve Youngs <steve@emchat.org>
7 ;; Created: Mon Jun 7 16:20:56 MSD 2004
8 ;; Keywords: emchat ICQ protocol
10 ;; This file is part of EMchat.
12 ;; Redistribution and use in source and binary forms, with or without
13 ;; modification, are permitted provided that the following conditions
16 ;; 1. Redistributions of source code must retain the above copyright
17 ;; notice, this list of conditions and the following disclaimer.
19 ;; 2. Redistributions in binary form must reproduce the above copyright
20 ;; notice, this list of conditions and the following disclaimer in the
21 ;; documentation and/or other materials provided with the distribution.
23 ;; 3. Neither the name of the author nor the names of any contributors
24 ;; may be used to endorse or promote products derived from this
25 ;; software without specific prior written permission.
27 ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
28 ;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29 ;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30 ;; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34 ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35 ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
36 ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
37 ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 ;; Testing UIN: 286012066, PASS: 123
42 ;; UIN: 321529598, PASS: 123
44 ;; The various network packets that make up the ICQv8 protocol.
46 ;; See: <http://www.emchat.org/~steve/icq/docs/>
47 ;; <http://iserverd1.khstu.ru/oscar/index.html>
53 (defvar emchat-add-user-success))
58 (defconst emchat-v8-FLAP-HELLO 1)
59 (defconst emchat-v8-FLAP-SNAC 2)
60 (defconst emchat-v8-FLAP-ERRORS 3)
61 (defconst emchat-v8-FLAP-LOGOFF 4)
62 (defconst emchat-v8-FLAP-PING 5)
64 (defconst emchat-v8-client-id-string
65 "ICQ Inc. - Product of ICQ (TM).2002a.5.37.1.3728.85"
66 "A string to identify ourselves as a nice well behaved ICQ client.")
68 (defconst emchat-v8-FLAP-VER-MAJOR 5)
69 (defconst emchat-v8-FLAP-VER-MINOR 37)
70 (defconst emchat-v8-FLAP-VER-LESSER 1)
71 (defconst emchat-v8-FLAP-VER-BUILD 3828)
72 (defconst emchat-v8-FLAP-VER-SUBBUILD 85)
74 (defconst emchat-v8-message-types
86 "List of valid message types.")
88 (defconst emchat-v8-valid-incoming-handlers
89 '(connected ; args: no
90 disconnected ; args: no
91 instant-message ; args: uin, msg &optional msg-type, time-stamp
92 offline-message ; args: uin, msg &optional msg-type, time-stamp
93 end-offline-messages ;
94 about-general ; general info about user
100 "List of valid incoming message handlers.
102 To bind on to handle incoming part of icq v8 proto.")
104 (defconst emchat-v8-valid-outgoing-handlers
106 ;; TODO: add some handlers
108 "List of valid outgoing message handlers.
110 To bind on to handle outgoing part of icq v8 proto.")
112 (defstruct emchat-v8-ctx
113 host port ; host/port we are currently connected
114 proc ; emchat network connection
115 (readingp 0) ; non-0 if we are currently reading from emchat context
116 sequence ; current flap sequence
118 incoming-buffer ; where incoming data stored
120 outgoing-buffer ; buffer for outgoing messages
123 state ; current state, connecting, connected
124 userinfo ; plist of userinfo '(uin <num> password <passwd>)
125 plist ; user defined plist
128 (defun emchat-v8-ctx-get-prop (ectx prop)
129 "Get ECTX's property PROP value."
130 (plist-get (emchat-v8-ctx-plist ectx) prop))
132 (defun emchat-v8-ctx-put-prop (ectx prop val)
133 "Put ECTX's property PROP value VAL."
134 (setf (emchat-v8-ctx-plist ectx)
135 (plist-put (emchat-v8-ctx-plist ectx) prop val)))
136 (put 'emchat-v8-ctx-put-prop 'lisp-indent-function 2)
138 (defun emchat-v8-ctx-rm-prop (ectx prop)
139 "Remove ECTX's property PROP."
140 (setf (emchat-v8-ctx-plist ectx)
141 (plist-remprop (emchat-v8-ctx-plist ectx) prop)))
143 (defun emchat-v8-ctx-get-incoming-handlers (ectx h)
144 (plist-get (emchat-v8-ctx-incoming-handlers ectx) h))
146 (defun emchat-v8-ctx-add-incoming-handler (ectx h f)
147 (setf (emchat-v8-ctx-incoming-handlers ectx)
148 (plist-put (emchat-v8-ctx-incoming-handlers ectx) h
149 (cons f (emchat-v8-ctx-get-incoming-handlers ectx h)))))
151 (defun emchat-v8-ctx-del-incoming-handler (ectx h f)
152 (setf (emchat-v8-ctx-incoming-handlers ectx)
153 (plist-put (emchat-v8-ctx-incoming-handlers ectx) h
154 (delete f (emchat-v8-ctx-get-incoming-handlers ectx h)))))
156 (defun emchat-v8-ctx-run-incoming-handler (ectx h &rest args)
157 (let ((ohs (emchat-v8-ctx-get-incoming-handlers ectx h))
160 (declare (special ih-arguments))
161 (apply 'run-hook-with-args (cons 'ohs (cons ectx args))))))
162 (put 'emchat-v8-ctx-run-incoming-handler 'lisp-indent-function 2)
164 (defun emchat-get-arg (kw)
165 (declare (special ih-arguments))
166 (plist-get ih-arguments kw))
169 (defmacro emchat-v8-ctx-msg-to-send (ectx)
170 `(emchat-v8-ctx-get-prop ,ectx 'message-to-send))
171 (defsetf emchat-v8-ctx-msg-to-send (ectx) (msg)
172 `(emchat-v8-ctx-put-prop ,ectx 'message-to-send ,msg))
174 (defmacro emchat-v8-ctx-pause-p (ectx)
175 `(emchat-v8-ctx-get-prop ,ectx 'pause-p))
176 (defsetf emchat-v8-ctx-pause-p (ectx) (pp)
179 (emchat-v8-ctx-put-prop ,ectx 'pause-p ,pp)
180 (setf (emchat-v8-ctx-msg-to-send ,ectx) ""))
181 (emchat-v8-ctx-rm-prop ,ectx 'pause-p)
182 (emchat-v8-send ,ectx (emchat-v8-ctx-msg-to-send ,ectx))
183 (setf (emchat-v8-ctx-msg-to-send ,ectx) "")))
186 (defvar emchat-v8-default-ctx nil
187 "Internal variable, do not modify.")
189 (defvar emchat-v8-connections nil
190 "List if emchat connections.
191 Internal variable, do not modify.")
193 (defcustom emchat-v8-debug t
194 "*Non-nil mean emchat protocol debugging is enabled."
198 (defvar emchat-debug-buffer "*emchat-debug*")
200 (defun emchat-v8-debug (msg &rest args)
202 (when emchat-v8-debug
204 (get-buffer-create emchat-debug-buffer)
206 (goto-char (point-max))
207 (insert (apply 'format msg args) "\n")))))
209 (defun emchat-v8-ctx ()
210 "Return default EMchat context."
211 emchat-v8-default-ctx)
214 (defsubst emchat-v8-flap-cid (flap)
216 (defsubst emchat-v8-flap-seq (flap)
218 (defsubst emchat-v8-flap-data (flap)
222 (defsubst emchat-v8-snac-family (snac)
224 (defsubst emchat-v8-snac-subtype (snac)
226 (defsubst emchat-v8-snac-flags (snac)
228 (defsubst emchat-v8-snac-rid (snac)
232 (defsubst emchat-v8-tlv-type (tlv)
234 (defsubst emchat-v8-tlv-len (tlv)
236 (defsubst emchat-v8-tlv-val (tlv)
238 (defsubst emchat-v8-tlv-str (tlv)
239 (aref (emchat-v8-tlv-val tlv) 0))
240 (defsubst emchat-v8-tlv-num (tlv)
241 (truncate (emchat-v8-string->number
242 (aref (emchat-v8-tlv-val tlv) 0) (truncate (emchat-v8-tlv-len tlv)))))
244 (defun emchat-v8-util-encrypt (password)
245 (let ((tb "\xf3\x26\x81\xc4\x39\x86\xdb\x92\x71\xa3\xb9\xe6\x53\x7a\x95\x7c")
246 (res (make-string (length password) ?\x00))
248 (while (< idx (length password))
249 (aset res idx (logxor (aref password idx) (aref tb (mod idx 16))))
253 (defun emchat-v8-create-ctx (uin &optional password &rest plist)
254 "Create new emchat context using UIN/PASSWORD.
255 PLIST is ectx properties list"
256 (let ((ectx (make-emchat-v8-ctx :state 'disconnected :plist plist)))
257 (setf (emchat-v8-ctx-userinfo ectx)
258 (list 'uin uin 'password password))
261 (defun emchat-v8-connect (ectx &optional server port)
262 "Connect to SERVER and PORT."
264 (setq server (or (emchat-v8-ctx-host ectx) "login.icq.com")))
266 (setq port (or (emchat-v8-ctx-host ectx) 5190)))
268 (setf (emchat-v8-ctx-host ectx) server)
269 (setf (emchat-v8-ctx-port ectx) port)
271 (let* ((proc (open-network-stream (format "emchat-v8-%s:%d" server port) nil
273 (state (emchat-v8-ctx-state ectx)))
275 (setf (emchat-v8-ctx-proc ectx) proc)
276 (setf (emchat-v8-ctx-sequence ectx) (random 65536))
278 ;; Store connection in emchat connections list
279 (push ectx emchat-v8-connections)
281 (set-process-filter proc 'emchat-v8-proc-filter-proccessing)
282 (set-process-sentinel proc 'emchat-v8-proc-sentinel)
284 (emchat-v8-debug "Connecting from state=%S" (emchat-v8-ctx-state ectx))
287 (cond ((or (eq state 'connecting)
289 (setf (emchat-v8-ctx-state ectx) 'connected))
290 (t (setf (emchat-v8-ctx-state ectx) 'connecting)))
293 (defun emchat-v8-close (ectx)
294 "Close ECTX connection."
295 (setf (emchat-v8-ctx-state ectx) 'closed)
296 (emchat-v8-proc-sentinel (emchat-v8-ctx-proc ectx)))
298 (defun emchat-v8-send (ectx msg)
299 "Using emchat context ECTX, send message MSG."
300 (if (not (emchat-v8-ctx-pause-p ectx))
301 (process-send-string (emchat-v8-ctx-proc ectx) msg)
302 ;; Add MSG to the pending data pending
303 (setf (emchat-v8-ctx-msg-to-send ectx)
304 (concat (emchat-v8-ctx-msg-to-send ectx) msg))))
305 (put 'emchat-v8-send 'lisp-indent-function 1)
307 (defun emchat-v8-send-flush (ectx)
308 "Flush ECTX's output buffer."
309 (when (> (length (emchat-v8-ctx-outgoing-buffer ectx)) 0)
311 (emchat-v8-ctx-proc ectx)
312 (emchat-v8-ctx-outgoing-buffer ectx))))
314 (defun emchat-v8-proc-find (proc)
315 "Find emchat context by PROC."
316 (let ((ecs emchat-v8-connections))
317 (while (and ecs (not (eq (emchat-v8-ctx-proc (car ecs)) proc)))
318 (setq ecs (cdr ecs)))
321 (defun emchat-v8-proc-sentinel (proc &optional event)
322 "Sentinel for emchat PROC."
323 (let ((ectx (emchat-v8-proc-find proc)))
324 (when (emchat-v8-ctx-p ectx)
326 (emchat-v8-debug "Removing process %S, state=%S, c-t=%S"
327 proc (emchat-v8-ctx-state ectx) (emchat-v8-ctx-get-prop ectx 'connect-tries))
328 (delete-process proc)
329 (setf (emchat-v8-ctx-incoming-buffer ectx) "") ;flush input buffer
331 (setq emchat-v8-connections (delq ectx emchat-v8-connections))
332 (when (eq (emchat-v8-ctx-state ectx) 'connected)
333 ;; Unexpected disconnection
334 (emchat-v8-ctx-run-incoming-handler ectx 'disconnect)))))
336 (defun emchat-v8-proc-filter-accumulator (proc out)
337 "Filter for emchat connection to accumulate data."
338 (let ((ectx (emchat-v8-proc-find proc)))
339 (when (emchat-v8-ctx-p ectx)
340 (setf (emchat-v8-ctx-incoming-buffer ectx)
341 (concat (emchat-v8-ctx-incoming-buffer ectx) out)))))
343 (defun emchat-v8-proc-filter-proccessing (proc out)
344 "Filter for emchat connection."
345 (let ((ectx (emchat-v8-proc-find proc)))
346 (when (emchat-v8-ctx-p ectx)
347 (setf (emchat-v8-ctx-incoming-buffer ectx)
348 (concat (emchat-v8-ctx-incoming-buffer ectx) out))
349 (enqueue-eval-event 'emchat-v8-fetch-handle-flaps ectx))))
351 (defvar emchat-v8-snacv-list
363 (defconst emchat-v8-snac-list
366 ((#x01 . #x01) "SRV_GEN_ERROR" emchat-v8-snac-srv-err)
367 ((#x01 . #x02) "CLI_READY" nil)
368 ((#x01 . #x03) "SRV_FAMILIES" emchat-v8-snac-srv-families)
369 ((#x01 . #x06) "CLI_RATESREQUEST" emchat-v8-snac-cli-ratesrequest)
370 ((#x01 . #x07) "SRV_RATES" emchat-v8-snac-srv-rates)
371 ;((#x01 . #x08) "CLI_ACKRATES" nil) ; handled in SRV_RATES
372 ((#x01 . #x0A) "SRV_RATE_CHANGE" emchat-v8-snac-srv-rate-change)
373 ((#x01 . #x0B) "SRV_SERVERPAUSE" emchat-v8-snac-srv-pause)
374 ((#x01 . #x0C) "CLI_ACKSERVERPAUSE" nil)
375 ((#x01 . #x0E) "CLI_REQINFO" nil)
376 ((#x01 . #x0F) "SRV_REPLYINFO" emchat-v8-snac-srv-replyinfo)
377 ((#x01 . #x12) "SRV_MIGRATIONREQ" emchat-v8-snac-srv-migrate)
378 ((#x01 . #x13) "SRV_MOTD" emchat-v8-snac-srv-motd)
379 ((#x01 . #x17) "CLI_FAMILIES" nil)
380 ((#x01 . #x18) "SRV_FAMILIES2" emchat-v8-snac-srv-families2)
381 ((#x01 . #x1E) "CLI_SETSTATUS" nil)
382 ((#x01 . #x21) "BART_REQUEST" emchat-v8-snac-bart-request)
383 ;; Family 2, Location
384 ((#x02 . #x01) "SRV_GEN_ERROR" emchat-v8-snac-srv-err)
385 ((#x02 . #x02) "CLI_REQLOCATION" nil)
386 ((#x02 . #x03) "SRV_REPLYLOCATION" emchat-v8-snac-srv-reply-location)
387 ((#x02 . #x04) "CLI_SETUSERINFO" nil)
388 ;; Family 3, Buddy lists (looks like AOL has turned this off)
389 ((#x03 . #x01) "SRV_CONTACTERR" emchat-v8-snac-srv-contact-err)
390 ((#x03 . #x02) "CLI_REQBUDDY" nil)
391 ((#x03 . #x03) "SRV_REPLYBUDDY" emchat-v8-snac-srv-reply-buddy)
392 ((#x03 . #x04) "CLI_ADDCONTACT" nil)
393 ((#x03 . #x05) "CLI_REMCONTACT" nil)
394 ((#x03 . #x0A) "SRV_REFUSE" emchat-v8-snac-srv-cont-refused)
395 ((#x03 . #x0B) "SRV_USERONLINE" emchat-v8-snac-srv-user-online)
396 ((#x03 . #x0C) "SRV_USEROFFLINE" emchat-v8-snac-srv-user-offline)
398 ((#x04 . #x01) "SRV_ICBMERR" emchat-v8-snac-srv-icbm-err)
399 ((#x04 . #x02) "CLI_SETICBM" nil)
400 ((#x04 . #x04) "CLI_REQICBM" nil)
401 ((#x04 . #x05) "SRV_REPLYICBM" emchat-v8-snac-srv-reply-icbm)
402 ((#x04 . #x06) "CLI_SENDMSG" nil)
403 ((#x04 . #x07) "SRV_RECVMSG" emchat-v8-snac-srv-recv-msg)
404 ((#x04 . #x0A) "SRV_MISSED_ICBM" emchat-v8-snac-srv-missed-icbm)
405 ((#x04 . #x0B) "SRV/CLI_ACKMSG" emchat-v8-snac-srv-ack-msg)
406 ((#x04 . #x0C) "SRV_SRVACKMSG" emchat-v8-snac-srv-srv-ack-msg)
407 ;; Family 5, Advertising NOT USED (thank god!)
408 ;; Family 6, Invitation (Invite somebody to AIM) erm, EMchat won't!!
409 ;; Family 7, Admin (AIM)
410 ;; Family 8, Popup Notices (AIM)
412 ((#x09 . #x01) "SRV_GEN_ERROR" emchat-v8-snac-srv-err)
413 ((#x09 . #x02) "CLI_REQBOS" nil)
414 ((#x09 . #x03) "SRV_REPLYBOS" emchat-v8-snac-srv-reply-bos)
415 ((#x09 . #x05) "CLI_ADDVISIBLE" emchat-v8-snac-cli-addvisible)
416 ((#x09 . #x06) "CLI_REMVISIBLE" emchat-v8-snac-cli-remvisible)
417 ((#x09 . #x07) "CLI_ADDINVISIBLE" emchat-v8-snac-cli-addinvisible)
418 ((#x09 . #x08) "CLI_REMINVISIBLE" emchat-v8-snac-cli-reminvisible)
419 ;; Family a [10], User Lookup (AIM and no longer used)
420 ;; Family b [11], Usage Stats Interval
421 ((#x0B . #x01) "SRV_GEN_ERROR" emchat-v8-snac-srv-err)
422 ((#x0B . #x02) "SRV_SETINTERVAL" emchat-v8-snac-srv-set-interval)
423 ;; Family c [12], Translation Service (deprecated (AIM))
424 ;; Family d [13], Chat Navigation (AIM)
425 ;; Family e [14], Chat Service (AIM)
426 ;; Family f [15], Directory Search (AIM)
427 ;; Family 10 [16], Server Stored Buddy Icons
428 ;; Family 13 [19], Server Side Info
429 ((#x13 . #x01) "SRV_GEN_ERROR" emchat-v8-snac-srv-err)
430 ((#x13 . #x02) "CLI_SSI_RIGHTS_REQUEST" emchat-v8-snac-cli-ssi-right-request)
431 ((#x13 . #x03) "SRV_SSI_RIGHTS_REPLY" emchat-v8-snac-srv-ssi-rights-reply)
432 ((#x13 . #x04) "CLI_SSI_REQUEST" emchat-v8-snac-cli-ssi-request)
433 ((#x13 . #x05) "CLI_SSI_CHECKOUT" emchat-v8-snac-cli-ssi-checkout)
434 ((#x13 . #x06) "SRV_SSI_REPLY" emchat-v8-snac-srv-ssi-reply)
435 ((#x13 . #x07) "CLI_SSI_ACTIVATE" emchat-v8-snac-cli-ssi-activate)
436 ((#x13 . #x08) "CLI_SSI_ADD" emchat-v8-snac-cli-ssi-add) ; broken
437 ((#x13 . #x09) "CLI_SSI_UPDATE" emchat-v8-snac-cli-ssi-update) ; not implimented yet
438 ((#x13 . #x0A) "CLI_SSI_DELETE" emchat-v8-snac-cli-ssi-delete) ; not implimented yet
439 ((#x13 . #x0E) "SRV_SSI_MOD_ACK" emchat-v8-snac-srv-ssi-mod-ack)
440 ((#x13 . #x0F) "SRV_SSI_UP_TO_DATE" emchat-v8-snac-srv-ssi-up-to-date)
441 ((#x13 . #x11) "CLI_SSI_EDIT_BEGIN" emchat-v8-snac-cli-ssi-edit-begin)
442 ((#x13 . #x12) "CLI_SSI_EDIT_END" emchat-v8-snac-cli-ssi-edit-end)
443 ((#x13 . #x14) "CLI_SSI_FUTURE_AUTH_GRANT" emchat-v8-snac-cli-ssi-future-auth-grant)
444 ((#x13 . #x15) "SRV_SSI_FUTURE_AUTH_GRANTED" emchat-v8-snac-srv-ssi-future-auth-granted)
445 ((#x13 . #x16) "CLI_SSI_DEL_YOURSELF" emchat-v8-snac-cli-ssi-del-yourself)
446 ((#x13 . #x18) "CLI_SSI_SEND_AUTH_REQUEST" emchat-v8-snac-cli-ssi-send-auth-request)
447 ((#x13 . #x19) "SRV_SSI_AUTH_REQUEST" emchat-v8-snac-srv-ssi-auth-request)
448 ((#x13 . #x1A) "CLI_SSI_AUTH_REPLY" emchat-v8-snac-cli-ssi-auth-reply)
449 ((#x13 . #x1B) "SRV_SSI_AUTH_REPLY" emchat-v8-snac-srv-ssi-auth-reply)
450 ((#x13 . #x1C) "SRV_SSI_YOU_WERE_ADDED" emchat-v8-snac-srv-ssi-you-were-added)
451 ;; Family 15 [21], ICQ Specific
452 ((#x15 . #x01) "SRV_TOICQERR" emchat-v8-snac-srv-toicqerr)
453 ;; This is like a family within a family... all the SNACS are #x15,#x02
454 ;; but they also have types and subtypes to differentiate between them.
455 ;; So we really don't need a function here.
456 ((#x15 . #x02) "CLI_TOICQSRV" nil)
457 ((#x15 . #x03) "SRV_FROMICQSRV" emchat-v8-snac-srv-fromicqsrv)
458 ;; Family 17 [23], Authorisation/Registration
459 ((#x17 . #x01) "SRV_REGREFUSED" emchat-v8-snac-srv-regrefused)
460 ((#x17 . #x05) "SRV_NEWUIN" emchat-v8-snac-srv-newuin)
461 ((#x17 . #x04) "CLI_REGISTERUSER" nil)
463 ((0 . 0) "unknown" nil))
464 "List of SNAC specs.")
466 (defun emchat-v8-recv-message (ectx h-type data)
468 (let* ((uin (emchat-v8-fetch-uin data))
469 (msg (emchat-v8-parse-message data
470 (list [2 number-swap] ;year
476 (tmsg (emchat-v8-parse-message data
477 (list [2 number-swap]
479 (ctext (substring (aref data 0) 0 (1- (length (aref data 0)))))
480 (time-stamp (list (truncate (nth 0 msg))
481 (truncate (nth 1 msg))
482 (truncate (nth 2 msg))
483 (truncate (nth 3 msg))
484 (truncate (nth 4 msg)))))
486 (emchat-v8-debug "Recv-message: '%S', tmsg='%S'" ctext tmsg)
489 (emchat-v8-ctx-run-incoming-handler ectx h-type
490 :uin uin :msg ctext :msg-type 'normal :time-stamp time-stamp)))
492 (defmacro emchat-v8-get-alist-value (code alist)
493 `(cdr (assq ,code ,alist)))
495 (defconst emchat-v8-countries-alist
500 (1021 . "Antigua & Barbuda")
504 (106 . "British Virgin Islands")
506 (108 . "Cayman Islands")
508 (110 . "Dominican Republic")
513 (1141 . "Saint Kitts and Nevis")
515 (116 . "St. Vincent & the Grenadines")
516 (117 . "Trinidad & Tobago")
517 (118 . "Turks & Caicos Islands")
519 (121 . "Puerto Rico")
520 (122 . "Saint Lucia")
521 (123 . "Virgin Islands (USA)")
522 (178 . "Canary Islands")
527 (218 . "Libyan Arab Jamahiriya")
533 (225 . "Cote d'Ivoire")
534 (226 . "Burkina Faso")
540 (232 . "Sierra Leone")
544 (236 . "Central African Republic")
546 (238 . "Cape Verde Islands")
547 (239 . "Sao Tome & Principe")
548 (240 . "Equatorial Guinea")
550 (242 . "Congo, (Rep. of the)")
551 (243 . "Congo, Democratic Republic of")
553 (245 . "Guinea-Bissau")
554 (246 . "Diego Garcia")
555 (247 . "Ascension Island")
569 (262 . "Reunion Island")
576 (269 . "Mayotte Island")
578 (27 . "South Africa")
582 (298 . "Faeroe Islands")
603 (373 . "Moldova, Republic of")
609 (379 . "Vatican City")
612 (3811 . "Yugoslavia - Serbia")
613 (382 . "Yugoslavia - Montenegro")
616 (387 . "Bosnia & Herzegovina")
617 (389 . "Macedonia (F.Y.R.O.M.)")
621 (4101 . "Liechtenstein")
622 (42 . "Czech Republic")
625 (44 . "United Kingdom")
633 (500 . "Falkland Islands")
636 (503 . "El Salvador")
641 (508 . "St. Pierre & Miquelon")
648 (56 . "Chile, Republic of")
652 (5901 . "French Antilles")
657 (594 . "French Guyana")
662 (599 . "Netherlands Antilles")
665 (6101 . "Cocos-Keeling Islands")
666 (6102 . "Cocos (Keeling) Islands")
672 (670 . "Saipan Island")
673 (6701 . "Rota Island")
674 (6702 . "Tinian Island")
675 (671 . "Guam, US Territory of")
676 (672 . "Christmas Island")
677 (6722 . "Norfolk Island")
680 (675 . "Papua New Guinea")
682 (677 . "Solomon Islands")
686 (681 . "Wallis & Futuna Islands")
687 (682 . "Cook Islands")
689 (684 . "American Samoa")
690 (685 . "Western Samoa")
692 (687 . "New Caledonia")
694 (689 . "French Polynesia")
696 (691 . "Micronesia, Federated States of")
697 (692 . "Marshall Islands")
702 (709 . "Turkmenistan")
705 (82 . "Korea, South")
707 (850 . "Korea, North")
724 (963 . "Syrian Arab Republic")
727 (966 . "Saudi Arabia")
730 (971 . "United Arabian Emirates")
737 (98 . "Iran (Islamic Republic of)")
742 (defmacro emchat-v8-get-country (code)
743 "Return country name according to country CODE."
744 `(emchat-v8-get-alist-value ,code emchat-v8-countries-alist))
746 (defconst emchat-v8-gender-alist
747 '((0 . "unspecified")
751 (defmacro emchat-v8-get-gender (code)
752 "Return gender name according to specified gender CODE."
753 `(emchat-v8-get-alist-value ,code emchat-v8-gender-alist))
755 (defconst emchat-v8-languages-alist
756 '((0 . "not specified")
831 (defmacro emchat-v8-get-language (code)
832 "Return language name according to language CODE."
833 `(emchat-v8-get-alist-value ,code emchat-v8-languages-alist))
835 (defconst emchat-v8-marital-alist
836 '((0 . "not specified")
838 (11 . "in a long-term relationship")
845 (defmacro emchat-v8-get-marital (code)
846 "Return marital name according to marital CODE."
847 `(emchat-v8-get-alist-value ,code emchat-v8-marital-alist))
851 ;;; Family #x13 (SSI - Server Side Info)
853 ;;; FIXME: This should most likely be used to set some max values in
854 ;;; EMchat, but I'm not that concerned seeing as though max contacts
856 (defun emchat-v8-snac-srv-ssi-rights-reply (ectx data &optional flags)
857 "SRV_SSI_RIGHTS_REPLY, SNAC(#x13, #x03)."
858 (let* ((tlvs (emchat-v8-fetch-tlvs data))
859 (limits (emchat-v8-tlv-val (emchat-v8-tlv-get tlvs 4)))
860 (mconts (emchat-v8-fetch-word limits)) ; max contacts
861 (mgrps (emchat-v8-fetch-word limits)) ; max groups
862 (mvconts (emchat-v8-fetch-word limits)) ; max visible contacts
863 (miconts (emchat-v8-fetch-word limits)) ; max invisible contacts
864 (mvibit (emchat-v8-fetch-word limits)) ; max vis/invis bitmasks
865 (mpres (emchat-v8-fetch-word limits)) ; max presence info fields
866 (mignores ; max ignore entries
869 (emchat-v8-fetch-word limits))
870 (emchat-v8-fetch-word limits)))
871 ;; rest of the thing is ignored for now (unknown stuff)
873 ;; not sure what to do with this yet, lets just log it for now
874 (emchat-v8-debug "SRV_SSI_RIGHTS_REPLY: Max number of...
878 Invisible Contacts=%d
879 Vis/Invis Bitmasks=%d
880 Presense Info Fields=%d
881 Ignore List Entries=%d"
882 mconts mgrps mvconts miconts mvibit mpres mignores)))
884 (defvar emchat-v8-ssi-count nil
885 "A place to store SSI entry count when it spans multiple packets.")
887 ;;; FIXME: handle BARTs
888 (defun emchat-v8-snac-srv-ssi-reply (ectx data &optional flags)
889 "SRV_SSI_REPLY, SNAC(#x13, #x06)."
891 (emchat-v8-fetch-byte data) ; skip, just a version number
892 (emchat-v8-fetch-word data)))
894 (push count emchat-v8-ssi-count)
896 (let* ((name (emchat-v8-fetch-bstr data))
897 (group (emchat-v8-fetch-word data))
898 (id (emchat-v8-fetch-word data))
899 (type (emchat-v8-fetch-word data))
900 (tlvs-len (emchat-v8-fetch-word data))
901 (tlvs (emchat-v8-fetch-n-tlvs data tlvs-len))
904 (setq ttype (emchat-v8-tlv-type (car tlvs)))
905 (setq tlen (emchat-v8-tlv-len (car tlvs)))
906 (setq tval (emchat-v8-tlv-val (car tlvs)))
907 (when (and (eq ttype #x131) (not (eq type #x14)))
908 (emchat-world-sync-ssi-maybe name group id tval))
909 (emchat-v8-debug "SSI_REPLY_TLV:
910 name=%S group=%S id=%S type=%S
911 ttype=%S tlength=%S tvalue=%S"
912 name group id type ttype tlen tval)
913 (setq tlvs (cdr tlvs)))))
914 (with-current-buffer (find-file-noselect emchat-world-rc-filename)
915 (when (buffer-modified-p)
917 (when (zerop (logand flags 1))
918 (when (> (length emchat-v8-ssi-count) 1)
919 (setq count (apply #'+ emchat-v8-ssi-count)))
920 (setq emchat-v8-ssi-count nil)
921 (setq lastupd (emchat-v8-fetch-time data))
922 (emchat-world-update-world-count count lastupd)
923 (emchat-v8-debug "SSI_REPLY: count=%S lastupd=%S" count lastupd))))
925 (defun emchat-v8-snac-srv-ssi-mod-ack (ectx data &optional flags)
926 "Server ack for buddy add/del/mod. SNAC(#x13, #x0E)."
927 (let ((retcodes '((#x0000 . "Success")
928 (#x0002 . "Item not found")
929 (#x0003 . "Item already exists")
930 (#x000A . "Invalid data")
931 (#x000C . "Limit exceeded")
932 (#x000D . "Can't add ICQ contact to AIM list")
933 (#x000E . "Authorisation required"))))
934 (setq emchat-add-user-success nil)
936 (let* ((code (emchat-v8-fetch-word data))
937 (retstr (cdr (assq code retcodes))))
938 (emchat-v8-debug "SRV_SSI_MOD_ACK: %s" retstr)
940 (emchat-v8-ctx-run-incoming-handler 'ectx 'new-user)
941 (emchat-log-error "SSI Modifications Error: %s" retstr))))))
943 (defun emchat-v8-snac-srv-ssi-up-to-date (ectx data &optional flags)
944 "Local copy of SSI is up to date. SNAC(#x13, #x0F).
946 This doesn't actually do anything because there isn't any point. It
947 sends back the mod time and item count, but you only get this packet
948 if your local SSI has the same mod time and item count."
949 (emchat-log-info "Local copy of SSI is up to date!")
950 (emchat-v8-debug "SRV_SSI_UP_TO_DATE: local SSI is up to date."))
953 (defun emchat-v8-snac-srv-ssi-auth-reply (ectx data &optional flags)
954 "SRV_SSI_AUTH_REPLY, SNAC (#x13 . #x1B)"
955 (let ((buin (emchat-v8-fetch-buin data))
956 (accept (emchat-v8-fetch-byte data))
957 (reason (emchat-v8-fetch-bstr data)))
958 (emchat-v8-debug "AUTHREPLY: from %d %s"
964 (emchat-v8-ctx-run-incoming-handler ectx 'auth-reject
965 :uin buin :msg reason :msg-type 'auth-reject)
966 (emchat-v8-ctx-run-incoming-handler ectx 'auth-accept
967 :uin buin :msg reason :msg-type 'auth-accept))))
969 (defun emchat-v8-snac-srv-ssi-you-were-added (ectx data &optional flags)
970 "SRV_ADDEDYOU, SNAC (#x13 . #x1C)"
971 (let ((buin (emchat-v8-fetch-buin data))
972 (msg "has added you to their contact list."))
973 (emchat-v8-debug "ADDEDYOU: by %d" buin)
974 (emchat-v8-ctx-run-incoming-handler ectx 'added-you
975 :uin buin :msg msg :msg-type 'added)))
977 (defun emchat-v8-snac-srv-ssi-future-auth-granted (ectx data &optional flags)
978 "Future auth has been given. SNAC(#x13, #x15)."
979 (let ((uin (emchat-v8-fetch-buin data))
980 (reason (emchat-v8-fetch-bstr data)))
981 (emchat-v8-debug "SRV_SSI_FUTURE_AUTH_GRANTED: %s grants auth because: %s"
983 (emchat-v8-ctx-run-incoming-handler ectx 'auth-accept
984 :uin uin :msg reason :msg-type 'auth-accept)))
986 (defun emchat-v8-snac-srv-ssi-auth-request (ectx data &optional flags)
987 "SRV_SSI_AUTH_REQUEST, SNAC (#x13 . #x19)"
988 (let ((buin (emchat-v8-fetch-buin data))
989 (reason (emchat-v8-fetch-bstr data)))
990 (emchat-v8-debug "AUTHREQ: from %d Reason: %S" buin reason)
991 (emchat-v8-ctx-run-incoming-handler ectx 'auth-request
992 :uin buin :msg reason :msg-type 'auth-request)))
994 ;;; Family #x15 (Old ICQ)
996 ;;; FIXME: complete this, a fair bit is still missing. Might need
997 ;;; splitting up into several functions
998 (defun emchat-v8-snac-srv-fromicqsrv (ectx data &optional flags)
999 "SRV_FROMICQSRV, SNAC(#x15, #x03)"
1000 (let* ((tlv1 (emchat-v8-tlv-val (emchat-v8-fetch-single-tlv data)))
1001 (len (emchat-v8-fetch-word-le tlv1))
1002 (my-uin (emchat-v8-fetch-uin tlv1))
1003 (type (emchat-v8-fetch-word-le tlv1))
1004 (seq (emchat-v8-fetch-word-le tlv1))
1005 (his-uin (cdr (assq seq (emchat-v8-ctx-get-prop ectx 'about-query-seq-uin)))))
1007 (setq len len my-uin my-uin)
1009 (emchat-v8-debug "FROMICQSRV: UIN: %S, Type=%d, seq=%d, tlv1=%S, data=%S"
1010 his-uin type seq tlv1 data)
1013 (emchat-v8-recv-message ectx 'offline-message tlv1))
1016 ;; Ack end of offline messages
1017 (emchat-v8-send ectx
1018 (emchat-v8-pack-meta-snac ectx 62))
1019 (emchat-v8-ctx-run-incoming-handler ectx 'end-offline-messages))
1022 (let ((subtype (emchat-v8-fetch-word-le tlv1))
1023 (result (emchat-v8-fetch-byte tlv1)))
1024 (emchat-v8-debug "SRV_META: Subtype=%d, result=%d, tlv1=%S" subtype result tlv1)
1027 (cond ((= subtype 200)
1030 (let ((nick (emchat-v8-fetch-lnts tlv1))
1031 (fname (emchat-v8-fetch-lnts tlv1))
1032 (sname (emchat-v8-fetch-lnts tlv1))
1033 (email (emchat-v8-fetch-lnts tlv1))
1034 (city (emchat-v8-fetch-lnts tlv1))
1035 (state (emchat-v8-fetch-lnts tlv1))
1036 (phone (emchat-v8-fetch-lnts tlv1))
1037 (fax (emchat-v8-fetch-lnts tlv1))
1038 (street (emchat-v8-fetch-lnts tlv1))
1039 (cellular (emchat-v8-fetch-lnts tlv1))
1040 (zip (emchat-v8-fetch-lnts tlv1))
1041 (country (emchat-v8-get-country
1042 (emchat-v8-fetch-word-le tlv1)))
1043 ;; The timezone the user lives in, as
1044 ;; multiples of 30minutes relative to UTC.
1045 (tz (emchat-v8-fetch-byte tlv1))
1046 (flags (emchat-v8-fetch-byte tlv1))
1047 (web-ind (= (emchat-v8-fetch-word-le tlv1) 1)))
1049 (emchat-v8-debug "GENERAL-Info: UIN: %d, Nick: %s"
1052 (emchat-v8-ctx-run-incoming-handler ectx 'about-general
1054 :nick nick :first-name fname :second-name sname
1055 :email email :city city :state state :phone phone
1056 :fax fax :street street :cellular cellular
1057 :zip-code zip :country country :tz tz
1058 :flags flags :web-indicator web-ind)))
1062 ;; Hey! Does anybody actually care about this? --lg
1066 (let ((age (emchat-v8-fetch-word-le tlv1))
1067 (gender (emchat-v8-get-gender
1068 (emchat-v8-fetch-byte tlv1)))
1069 (homepage (emchat-v8-fetch-lnts tlv1))
1070 (birth-year (emchat-v8-fetch-word-le tlv1))
1071 (birth-month (emchat-v8-fetch-byte tlv1))
1072 (birth-day (emchat-v8-fetch-byte tlv1))
1073 (lang1 (emchat-v8-get-language
1074 (emchat-v8-fetch-byte tlv1)))
1075 (lang2 (emchat-v8-get-language
1076 (emchat-v8-fetch-byte tlv1)))
1077 (lang3 (emchat-v8-get-language
1078 (emchat-v8-fetch-byte tlv1)))
1080 (emchat-v8-fetch-word-le tlv1) ; skip
1081 (emchat-v8-fetch-lnts tlv1)))
1082 (ostate (emchat-v8-fetch-lnts tlv1))
1083 (ocountry (emchat-v8-get-country
1084 (emchat-v8-fetch-word-le tlv1)))
1085 (marital (emchat-v8-get-marital
1086 (emchat-v8-fetch-word-le tlv1))))
1087 (emchat-v8-ctx-run-incoming-handler ectx 'about-more
1088 :uin his-uin :age age :gender gender :homepage homepage
1089 :birth-year birth-year :birth-month birth-month
1090 :birth-day birth-day :lang1 lang1 :lang2 lang2
1091 :lang3 lang3 :ocity ocity :ostate ostate
1092 :ocountry ocountry :marital marital)))
1102 (let ((about-user (emchat-v8-fetch-lnts tlv1)))
1103 (emchat-v8-debug "USER ABOUT-Info: %S" about-user)
1104 (emchat-v8-ctx-run-incoming-handler ectx 'about-about
1105 :uin his-uin :about about-user)))
1115 ;; Search found a user
1116 (let ((uin (progn (emchat-v8-fetch-word-le tlv1)
1117 (emchat-v8-fetch-uin tlv1)))
1118 (nick (emchat-v8-fetch-lnts tlv1))
1119 (first-name (emchat-v8-fetch-lnts tlv1))
1120 (last-name (emchat-v8-fetch-lnts tlv1))
1121 (email (emchat-v8-fetch-lnts tlv1))
1122 (auth (emchat-v8-fetch-byte tlv1))
1123 (status (emchat-v8-fetch-word-le tlv1))
1124 (gender (emchat-v8-get-gender
1125 (emchat-v8-fetch-byte tlv1)))
1126 (age (emchat-v8-fetch-word-le tlv1))
1127 (missed (emchat-v8-fetch-word-le tlv1)))
1128 (emchat-v8-debug "FOUND USER: UIN=%d, Nick=%s, missed=%d" uin nick missed)
1129 (emchat-v8-ctx-run-incoming-handler ectx 'search-found
1131 :first-name first-name :last-name last-name
1132 :email email :auth auth :status status :gender gender
1133 :age age :missed missed)))
1136 ;; Search found a user (the last match from the search)
1137 (let ((uin (progn (emchat-v8-fetch-word-le tlv1)
1138 (emchat-v8-fetch-uin tlv1)))
1139 (nick (emchat-v8-fetch-lnts tlv1))
1140 (first-name (emchat-v8-fetch-lnts tlv1))
1141 (last-name (emchat-v8-fetch-lnts tlv1))
1142 (email (emchat-v8-fetch-lnts tlv1))
1143 (auth (emchat-v8-fetch-byte tlv1))
1144 (status (emchat-v8-fetch-word-le tlv1))
1145 (gender (emchat-v8-get-gender
1146 (emchat-v8-fetch-byte tlv1)))
1147 (age (emchat-v8-fetch-word-le tlv1))
1148 (missed (emchat-v8-fetch-word-le tlv1)))
1149 (emchat-v8-debug "FOUND USER: UIN=%d, Nick=%s, missed=%d" uin nick missed)
1150 (emchat-v8-ctx-run-incoming-handler ectx 'search-found-last
1152 :first-name first-name :last-name last-name
1153 :email email :auth auth :status status :gender gender
1154 :age age :missed missed)))
1158 (defun emchat-v8-snac-srv-toicqerr (ectx data &optional flags)
1159 "SRV_TOICQERR, SNAC(0x15, 0x01)"
1160 (let ((ecode (emchat-v8-fetch-word data))
1161 (tlv1 (emchat-v8-fetch-single-tlv data)))
1162 (error "Malformed TOICQ request" ecode tlv1)))
1164 (defun emchat-v8-snac-srv-set-interval (ectx data &optional flags)
1165 "SRV_SETINTERVAL, SNAC(0x0B, 0x02)"
1166 (let ((ival (emchat-v8-fetch-word data)))
1167 (emchat-v8-debug "User info interval: %S" ival)
1168 (emchat-v8-ctx-put-prop ectx 'user-info-interval ival)))
1170 (defun emchat-v8-snac-srv-icbm-err (ectx data &optional flags)
1172 (let* ((ival (emchat-v8-fetch-word data))
1173 (err (cond ((= ival 4) "User offline")
1174 ((= ival 9) "Client does not understand type-2 mesasges")
1175 ((= ival 14) "Packet was malformed")
1177 (emchat-v8-debug "ICBMERR: %d/%s" ival err)))
1179 (defun emchat-v8-snac-srv-reply-icbm (ectx data &optional flags)
1180 "SRV_REPLICBM, SNAC(#x04, #x05)"
1183 (defun emchat-v8-snac-srv-replyinfo (ectx data &optional flags)
1184 "SRV_REPLYINFO, SNAC(1, f)"
1185 ;; BUIN xx .. UIN The UIN this information is about.
1186 ;; WORD.B 00 00 WARNING Probably a warning level left over from OSCAR.
1187 ;; WORD.B 00 xx COUNT Total number of TLVs to follow.
1188 ;; TLV(1) 00 01 00 02 00 80 UNKNOWN Unknown.
1189 ;; TLV(12) 00 0c 00 25 ... CLI2CLI Direct connection info, see CLI_SETSTATUS SNAC(1,30).
1190 ;; TLV(15) 00 0f 00 04 xx xx xx xx UNKNOWN Number of seconds that user has been online?
1191 ;; TLV(2) 00 02 00 04 TIME MEMBERTIME The member since time.
1192 ;; TLV(3) 00 03 00 04 TIME ONLINETIME The online since time.
1193 ;; TLV(5) 00 05 00 04 TIME UNKNOWN Some unknown time.
1194 ;; TLV(6) 00 06 00 04 xx xx xx xx STATUS The current online status.
1195 ;; TLV(30) 00 1e 00 04 00 00 00 00 UNKNOWN Unknown: empty.
1196 ; (let* ((uin (emchat-v8-fetch-buin data))
1198 ; (emchat-v8-fetch-word data) ; skip (warning)
1199 ; (emchat-v8-fetch-word data) ; skip (tlv count)
1200 ; (emchat-v8-fetch-tlvs data)))
1201 ; (tlv12 (emchat-v8-tlv-get tlvs 12))) ; CLI2CLI
1203 ; (emchat-v8-debug "SRV_REPLYINFO: UIN=%d tlv12=%S" uin tlv12)
1207 (defun emchat-v8-snac-srv-reply-buddy (ectx data &optional flags)
1208 "SRV_REPLYBUDDY, SNAC(0x03, 0x03)"
1209 (let* ((tlvs (emchat-v8-fetch-tlvs data))
1210 (muaicl (emchat-v8-tlv-get tlvs 1)) ;maximum uins allowed in contact list
1211 (mpchuu (emchat-v8-tlv-get tlvs 2))) ;maximum number of people that can have our uin in contact list
1213 (emchat-v8-ctx-put-prop ectx 'maximum-uins (emchat-v8-tlv-num muaicl)))
1215 (emchat-v8-ctx-put-prop ectx 'maximum-people (emchat-v8-tlv-num mpchuu)))))
1217 (defun emchat-v8-snac-srv-user-online (ectx data &optional flags)
1218 "SRV_USERONLINE, SNAC(0x03, 0x0B)."
1219 (let* ((buin (emchat-v8-fetch-buin data))
1221 (emchat-v8-fetch-data data 4) ; skip
1222 (emchat-v8-fetch-tlvs data)))
1223 (ts (emchat-v8-tlv-get tlvs 6))
1224 ;; XXX use only last 2 bytes of status
1225 (new-status (and ts (emchat-v8-find-status
1227 (emchat-v8-fetch-word (emchat-v8-tlv-val ts))
1228 (emchat-v8-fetch-word (emchat-v8-tlv-val ts)))))))
1229 (emchat-v8-debug "SRV_USERONLINE: uin=%d status=%S/%S"
1232 (emchat-v8-ctx-run-incoming-handler ectx 'status-update
1235 (defun emchat-v8-snac-srv-user-offline (ectx data &optional flags)
1236 "SRV_USEROFFLINE, SNAC(0x03, 0x0C)"
1237 (let ((buin (emchat-v8-fetch-buin data)))
1238 (emchat-v8-debug "SRV_USEROFFLINE: uin=%d" buin)
1239 (emchat-v8-ctx-run-incoming-handler ectx 'status-update
1242 (defun emchat-v8-snac-srv-reply-location (ectx data &optional flags)
1243 "SRV_REPLYLOCATION, SNAC(0x02, 0x03)."
1245 (let* ((tlvs (emchat-v8-fetch-tlvs data))
1246 (mcap (emchat-v8-tlv-get tlvs 2)))
1248 ;; Set maximum capabilities
1249 (emchat-v8-debug "max capabilities: %S" (emchat-v8-tlv-num mcap))
1250 (emchat-v8-ctx-put-prop ectx 'maximum-capabilities (emchat-v8-tlv-num mcap)))))
1252 (defun emchat-v8-snac-srv-families (ectx data &optional flags)
1253 "SRV_FAMILIES, SNAC(0x01, 0x03)."
1255 (while (> (length (aref data 0)) 0)
1257 (cons (emchat-v8-fetch-word data) srv-families)))
1258 (emchat-v8-ctx-put-prop ectx 'server-families srv-families))
1260 (emchat-v8-debug "SRV-FAMILIES %S" (emchat-v8-ctx-get-prop ectx 'server-families))
1261 (emchat-v8-snac-cli-families ectx))
1263 (defun emchat-v8-snac-srv-families2 (ectx data &optional flags)
1264 "SRV_FAMILIES2, SNAC(0x01, 0x12)."
1265 (emchat-v8-debug "SRV-FAMILIES2 %S" data)
1268 (defun emchat-v8-snac-bart-request (ectx data &optional flags)
1269 "BART_REQUEST, SNAC(0x01, 0x21)."
1270 (let* ((type (emchat-v8-fetch-word data))
1271 (flag (emchat-v8-fetch-byte data))
1272 (len_opaque (emchat-v8-fetch-byte data))
1273 (opaque (emchat-v8-fetch-data data len_opaque)))
1274 (emchat-v8-debug "[BART]...
1279 type flag len_opaque opaque)))
1281 (defun emchat-v8-snac-srv-rates (ectx data &optional flags)
1282 "SRV_RATES, SNAC(0x01, 0x07)."
1283 (let ((nr (emchat-v8-parse-message
1286 [2 emchat-v8-length-1]
1288 ([2 number] ; Rate class ID
1289 [4 number] ; Window size
1290 [4 number] ; Clear level
1291 [4 number] ; Alert level
1292 [4 number] ; Limit level
1293 [4 number] ; Disconnect level
1294 [4 number] ; Current level
1295 [4 number] ; Max level
1296 [4 number] ; last time
1297 [1 number])] ; current state
1299 ([2 number] ; Rate class ID
1300 [2 emchat-v8-length-2] ; number of pairs in group
1301 [emchat-v8-length-2 ([4 number])])]))))
1303 (emchat-v8-debug "SRV_RATES: %S" nr)
1307 (emchat-v8-send ectx
1308 (emchat-v8-pack-snac ectx '(#x01 . #x08)
1310 (mapcar 'emchat-v8-pack-word (mapcar 'car (nth 1 nr)))))))
1313 (defun emchat-v8-snac-srv-rate-change (ectx data &optional flags)
1314 "SRV_RATE_CHANGE, SNAC(#x01, #x0A)."
1315 (let ((code (emchat-v8-fetch-word data))
1316 (rateid (emchat-v8-fetch-word data))
1317 (winsize (emchat-v8-fetch-dword data))
1318 (clear (emchat-v8-fetch-dword data))
1319 (alert (emchat-v8-fetch-dword data))
1320 (limit (emchat-v8-fetch-dword data))
1321 (discon (emchat-v8-fetch-dword data))
1322 (currl (emchat-v8-fetch-dword data))
1323 (max (emchat-v8-fetch-dword data))
1324 (ltime (emchat-v8-fetch-dword data))
1325 (currs (emchat-v8-fetch-byte data)))
1327 "[SRV_RATE_EXCEEDED]:
1334 Disconnect Level: %d
1339 code rateid winsize clear alert limit discon currl max ltime currs)
1342 (2 (emchat-log-info "You've reached the rate limit: %d
1343 Chill out, take a break, have a coffee." alert))
1344 (3 (emchat-log-error "Rate limit passed: %d
1345 Hope you get to read this before you get disconnected" discon))
1348 (defun emchat-v8-snac-srv-pause (ectx data &optional flags)
1349 "SRV_SERVERPAUSE, SNAC(1, B)."
1350 ;; Send CLI_ACKSERVERPAUSE snac
1351 (emchat-v8-send ectx
1352 (emchat-v8-pack-snac ectx '(#x09 . #x02)
1353 (apply 'concat (mapcar #'(lambda (fam)
1354 (emchat-v8-pack-word (car fam)))
1355 emchat-v8-snacv-list))))
1357 ;; Mark ECTX as in pause, until SRV_MIGRATIONREQ is received
1358 (setf (emchat-v8-ctx-pause-p ectx) t))
1360 (defun emchat-v8-snac-srv-migrate (ectx data &optional flags)
1361 "SRV_MIGRATIONREQ, SNAC(1, 12)."
1363 (emchat-v8-fetch-word data)
1364 (emchat-v8-fetch-tlvs data)))
1365 (tlv5 (emchat-v8-tlv-get tlvs 5))
1366 (tlv6 (emchat-v8-tlv-get tlvs 6)))
1368 ;; Close current connection
1369 (emchat-v8-close ectx)
1371 (let* ((nsrv (split-string (emchat-v8-tlv-str tlv5) ":"))
1373 (port (string-to-int (nth 1 nsrv))))
1374 (emchat-v8-debug "Migrating to new server: %s:%d" addr port)
1375 ;; Store cookie and reconnect
1376 (emchat-v8-ctx-put-prop ectx 'cli-cookie (emchat-v8-tlv-str tlv6))
1377 (emchat-v8-connect ectx addr port))))
1379 (defun emchat-v8-snac-srv-motd (ectx data &optional flags)
1380 "SRV_MOTD, SNAC(1, 13)."
1381 (emchat-v8-debug "SRV_MOTD")
1383 (emchat-v8-snac-cli-ratesrequest ectx)
1384 (emchat-v8-snac-cli-reqinfo ectx)
1387 (emchat-v8-snac-cli-reqlocation ectx)
1388 (emchat-v8-snac-cli-reqbuddy ectx)
1389 (emchat-v8-snac-cli-reqicbm ectx)
1390 (emchat-v8-snac-cli-reqbos ectx)
1392 (emchat-v8-ctx-run-incoming-handler ectx 'connected))
1394 (defconst emchat-v8-msg-types
1395 '((0 . automatic) ; An automatic message
1396 (1 . normal) ; A plain normal message
1397 (2 . chat-request) ; A chat request
1398 (3 . file-transfer-request) ; A file transfer request
1399 (4 . url) ; An URL message. The message consists of the description and the url
1400 (6 . auth-request) ; An authorization request
1401 (7 . auth-reject) ; An authorization reject message
1402 (8 . auth-accept) ; An authorization accept message
1403 (12 . added) ; You were added to the sender's contact list
1404 (13 . web-pager) ; A message sent through www.icq.com's web pager
1405 (14 . email-pager) ; A message sent through the email pager ([uin]@pager.icq.com)
1406 (19 . contact-list) ; A contact list message
1407 (26 . extended) ; An extended message. The packet will contain more data
1408 (1000 . get-away) ; A message requesting the "away" auto message
1409 (1001 . get-occ) ; A message requesting the "occupied" auto message
1410 (1002 . get-na) ; A message requesting the "not available" auto message
1411 (1003 . get-dnd) ; A message requesting the "do not disturb" auto message
1412 (1004 . get-ffc) ; A message requesting the "free for chat" auto message
1414 "List of message types.")
1416 (defconst emchat-v8-msg-mass-flag #x8000
1417 "If set, message was sent to several recipients.")
1419 (defun emchat-v8-snac-srv-recv-msg (ectx data &optional flags)
1420 "SRV_RECVMSG, SNAC(4, 7)."
1421 (emchat-v8-debug "data here: %S" data)
1422 (let ((midtime (emchat-v8-fetch-time data))
1423 (midrand (emchat-v8-fetch-dword data))
1424 (type (emchat-v8-fetch-word data))
1425 (uin (emchat-v8-fetch-buin data))
1426 (warn (emchat-v8-fetch-word data))
1427 (count (emchat-v8-fetch-word data))
1428 (tlvs (emchat-v8-fetch-tlvs data)))
1431 (emchat-v8-debug "Got message from %S, mt/mr/t/w/c=%S/%S/%S/%S/%S, tlvs=%S"
1432 uin midtime midrand type warn count tlvs)
1436 (let* ((tlvals (emchat-v8-fetch-tlvs
1437 (emchat-v8-tlv-val (emchat-v8-tlv-get tlvs 2))))
1438 (caps (emchat-v8-fetch-byte
1439 (emchat-v8-tlv-val (emchat-v8-tlv-get tlvals 1281))))
1440 (mtlval (emchat-v8-tlv-val
1441 (emchat-v8-tlv-get tlvals 257)))
1442 (menc (emchat-v8-fetch-word mtlval))
1444 (emchat-v8-fetch-word mtlval) ; skip
1445 (emchat-v8-fetch-string mtlval))))
1447 (emchat-v8-debug "Normal message: caps/menc=%d/%d, msg='%s'"
1449 (emchat-v8-ctx-run-incoming-handler ectx 'instant-message
1450 :uin uin :msg msg :msg-type 'normal)))
1455 (emchat-v8-debug "MSG[%d]: here" type))
1459 (let* ((tlv5 (emchat-v8-tlv-val (emchat-v8-tlv-get (nreverse tlvs) 5)))
1460 (uin (truncate (emchat-v8-fetch-uin tlv5)))
1461 (mtype (emchat-v8-fetch-word-le tlv5))
1462 (msg (emchat-v8-fetch-lnts tlv5))
1464 ;; Adjust MTYPE to remove flag fields (MSGF_MASS)
1465 (setq mtype (logand mtype (lognot emchat-v8-msg-mass-flag)))
1466 (setq msg-type (cdr (assoc mtype emchat-v8-msg-types)))
1468 (emchat-v8-ctx-run-incoming-handler ectx 'instant-message
1469 :uin uin :msg msg :msg-type msg-type)))
1471 (t (error "Unknown message type")))))
1473 (defun emchat-v8-snac-srv-missed-icbm (ectx data &optional flags)
1474 "SRV_MISSED_ICBM, SNAC(4, 10)."
1476 (emchat-v8-fetch-word data) ; skip channel
1477 (emchat-v8-fetch-buin data)))
1479 (emchat-v8-fetch-word data) ; skip warn
1480 (dotimes (n (emchat-v8-fetch-word data)) ; skip tlvs
1481 (emchat-v8-fetch-single-tlv data))
1482 (emchat-v8-fetch-word data)))
1483 (rn (emchat-v8-fetch-word data))
1484 (reasons '((0 . "Invalid message")
1485 (1 . "Message too large")
1486 (2 . "Message rate limit exceeded")
1487 (3 . "Sender too evil (sender warn level > your max_msg_sevil)")
1488 (4 . "You are too evil (sender max_msg_revil > your warn level)")))
1489 (reason (or (cdr (assq rn reasons)) "Unknown reason")))
1490 (emchat-v8-ctx-run-incoming-handler ectx 'missed-message
1491 :uin buin :missed-messages mmsgs :reason reason)))
1493 (defun emchat-v8-snac-srv-contact-err (ectx data &optional flags)
1494 "SRV_CONTACTERR, SNAC(3, #x01)."
1495 (let* ((ercode (emchat-v8-fetch-word data))
1496 (errmsg (cond ((= ercode #x0E) "Empty UIN list sent")
1497 ((= ercode #x14) "Non existant UIN")
1498 ((= ercode #x15) "Contact list full"))))
1499 (emchat-v8-debug "[SRV_CONTACTERR]: Code=%d (0x%1$02X), Msg=%s" ercode errmsg)
1500 (emchat-v8-ctx-run-incoming-handler ectx 'srv-contacterr :reason errmsg)))
1502 (defun emchat-v8-snac-srv-err (ectx data &optional flags)
1503 "SRV_GEN_ERR, SNAC(1, #x01)."
1504 (let* ((ercode (emchat-v8-fetch-word data))
1505 (errmsg (cond ((= ercode #x01) "Invalid SNAC header.")
1506 ((= ercode #x02) "Server rate limit exceeded")
1507 ((= ercode #x03) "Client rate limit exceeded")
1508 ((= ercode #x04) "Recipient is not logged in")
1509 ((= ercode #x05) "Requested service unavailable")
1510 ((= ercode #x06) "Requested service not defined")
1511 ((= ercode #x07) "You sent obsolete SNAC")
1512 ((= ercode #x08) "Not supported by server")
1513 ((= ercode #x09) "Not supported by client")
1514 ((= ercode #x0A) "Refused by client")
1515 ((= ercode #x0B) "Reply too big")
1516 ((= ercode #x0C) "Responses lost")
1517 ((= ercode #x0D) "Request denied")
1518 ((= ercode #x0E) "Incorrect SNAC format")
1519 ((= ercode #x0F) "Insufficient rights")
1520 ((= ercode #x10) "In local permit/deny (recipient blocked)")
1521 ((= ercode #x11) "Sender too evil")
1522 ((= ercode #x12) "Receiver too evil")
1523 ((= ercode #x13) "User temporarily unavailable")
1524 ((= ercode #x14) "No match")
1525 ((= ercode #x15) "List overflow")
1526 ((= ercode #x16) "Request ambiguous")
1527 ((= ercode #x17) "Server queue full")
1528 ((= ercode #x18) "Not while on AOL")
1529 (t "Unknown error"))))
1530 (emchat-v8-debug "SRV_GEN_ERR: %s" errmsg)
1531 (emchat-v8-ctx-run-incoming-handler ectx 'srv-error :reason errmsg)))
1533 (defun emchat-v8-snac-srv-reply-bos (ectx data &optional flags)
1534 "SRV_REPLYBOS, SNAC(9, 3)."
1535 (emchat-v8-snac-cli-setuserinfo ectx)
1536 (emchat-v8-snac-cli-setstatus
1537 ectx (emchat-v8-ctx-get-prop ectx 'initial-status))
1538 (emchat-v8-snac-cli-ready ectx)
1539 ;; This is the now unsupported local-only type of contact list.
1540 ;; (emchat-v8-snac-cli-add-contact ectx)
1541 (emchat-v8-snac-cli-reqofflinemsgs ectx))
1543 (defun emchat-v8-snac-srv-srv-ack-msg (ectx data &optional flags)
1544 "SRV_SRVACKMSG, SNAC (4 . #x0C)"
1546 (emchat-v8-fetch-data data 8) ; skip
1547 (emchat-v8-fetch-word data)))
1548 (buin (emchat-v8-fetch-buin data)))
1549 (emchat-v8-debug "SRVACKMSG: type=%d uin=%d" type buin)
1554 ;;; Family #x13 (SSI -- Server Side Info)
1556 (defun emchat-v8-snac-cli-ssi-right-request (ectx)
1557 "Request rights/limitations for SSI. SNAC(#x13, #x02)."
1558 (emchat-v8-send ectx
1559 (emchat-v8-pack-snac ectx '(#x13 . #x02))))
1561 (defun emchat-v8-snac-cli-ssi-request (ectx)
1562 "Request server side info. SNAC(#x13, #x04)."
1563 (emchat-v8-send ectx
1564 (emchat-v8-pack-snac ectx '(#x13 . #x04))))
1566 (defun emchat-v8-snac-cli-ssi-checkout (ectx)
1567 "Checkout SSI list if local copy is out of date. SNAC(#x13, #x05)."
1568 (let ((num (emchat-world-ssi-count))
1569 (modt (emchat-world-ssi-mod-time)))
1570 (emchat-v8-send ectx
1571 (emchat-v8-pack-snac ectx '(#x13 . #x05)
1572 (emchat-v8-pack-time modt)
1573 (emchat-v8-pack-word num)))))
1575 (defun emchat-v8-snac-cli-ssi-activate (ectx)
1576 "Activate SSI. SNAC(#x13, #x07)."
1577 (emchat-v8-send ectx
1578 (emchat-v8-pack-snac ectx '(#x13 . #x07))))
1580 ;;; FIXME: This isn't working.
1581 (defun emchat-v8-snac-cli-ssi-add (ectx uin grp id nick)
1582 "Add contacts to SSI. SNAC(#x13, #x08)."
1583 (emchat-v8-send ectx
1584 (emchat-v8-pack-snac ectx '(#x13 . #x08)
1585 (emchat-v8-pack-bstr uin)
1586 (emchat-v8-pack-word grp)
1587 (emchat-v8-pack-word id)
1588 (emchat-v8-pack-word #x0000)
1589 (emchat-v8-pack-tlv #x0131 nick))))
1592 (defalias 'emchat-v8-snac-cli-ssi-update #'ignore)
1593 ;; (defun emchat-v8-snac-cli-ssi-update (ectx &rest entries)
1594 ;; "Update existing SSI entries. SNAC(#x13, #x09)."
1595 ;; (emchat-v8-debug "CLI_SSI_UPDATE: somebody impliment me"))
1598 (defalias 'emchat-v8-snac-cli-ssi-delete #'ignore)
1599 ;; (defun emchat-v8-snac-cli-ssi-delete (ectx &rest entries)
1600 ;; "Delete existing SSI entries. SNAC(#x13, #x0A)."
1601 ;; (emchat-v8-debug "CLI_SSI_DELETE: somebody impliment me"))
1602 (defalias 'emchat-v8-snac-cli-ssi-edit-begin #'ignore)
1603 ;; (defun emchat-v8-snac-cli-ssi-edit-begin (ectx &rest args)
1604 ;; "Begin SSI edits. SNAC(#x13, #x11)."
1605 ;; (emchat-v8-send ectx
1606 ;; (emchat-v8-pack-snac ectx '(#x13 . #x11))))
1607 (defalias 'emchat-v8-snac-cli-ssi-edit-end #'ignore)
1608 ;; (defun emchat-v8-snac-cli-ssi-edit-end (ectx &rest args)
1609 ;; "End SSI edits. SNAC(#x13, #x12)."
1610 ;; (emchat-v8-send ectx
1611 ;; (emchat-v8-pack-snac ectx '(#x13 . #x12))))
1613 (defun emchat-v8-snac-cli-ssi-future-auth-grant (ectx uin reason)
1614 "Give future auth grant. SNAC(#x13, #x14)."
1615 (emchat-v8-send ectx
1616 (emchat-v8-pack-snac ectx '(#x13 . #x14)
1617 (emchat-v8-pack-byte (length (number-to-string uin)))
1618 (emchat-v8-pack-buin uin)
1619 (emchat-v8-pack-dword 0))))
1621 (defun emchat-v8-snac-cli-ssi-del-yourself (ectx uin)
1622 "Delete yourself from someone's contact list. SNAC(#x13, #x16)."
1623 (emchat-v8-send ectx
1624 (emchat-v8-pack-snac ectx '(#x13 . #x16)
1625 (emchat-v8-pack-buin uin))))
1627 (defun emchat-v8-snac-cli-ssi-send-auth-request (ectx uin msg)
1628 "Send auth request. SNAC(#x13, #x18)."
1629 (emchat-v8-send ectx
1630 (emchat-v8-pack-snac ectx '(#x13 . #x18)
1631 (emchat-v8-pack-buin uin)
1632 (emchat-v8-pack-bstr msg))))
1634 (defun emchat-v8-snac-cli-ssi-auth-reply (ectx uin reply &optional reason)
1635 "Reply to auth-request. SNAC(#x13, #x1A)."
1636 (emchat-v8-send ectx
1637 (emchat-v8-pack-snac ectx '(#x13 . #x1A)
1638 (emchat-v8-pack-buin uin)
1639 (emchat-v8-pack-byte reply)
1640 (emchat-v8-pack-bstr reason)
1641 (emchat-v8-pack-word 0))))
1644 (defun emchat-v8-snac-cli-setuserinfo (ectx)
1648 (defconst emchat-v8-status-alist
1649 `((offline . ,(* 256.0 256 256 256))
1650 (invisible . #x100) ;user is invisible
1651 (dnd . #x02) ;user does not want to be disturbed
1652 (occupied . #x10) ;user is occupied
1653 (na . #x04) ;user not available
1654 (away . #x01) ;user is away
1655 (ffc . #x20) ;user is free for chat
1656 (online . #x00) ;user is online
1657 (set-invisible . #x100)
1659 (set-occupied . #x11)
1663 (web-aware . #x010000)
1664 (allow-ip . #x020000)
1665 (birthday . #x80000)
1666 (dcauth . #x10000000)
1667 (dccontact . #x20000000))
1670 (defun emchat-v8-find-status (num)
1671 "Find statu by NUM."
1672 (setq num (logand num #x0000ffff))
1673 (let ((statuses (cdr emchat-v8-status-alist)))
1674 (while (and statuses
1675 (zerop (logand num (cdar statuses))))
1676 (setq statuses (cdr statuses)))
1677 (or (caar statuses) 'online)))
1679 (defun emchat-v8-snac-cli-setstatus (ectx &optional status)
1680 "Set status, SNAC(1, 30)."
1681 (setq status (apply 'logior
1682 (mapcar #'(lambda (st)
1683 (cdr (assoc st emchat-v8-status-alist)))
1686 (emchat-v8-send ectx
1687 (emchat-v8-pack-snac ectx '(#x01 . #x1E)
1688 (emchat-v8-pack-tlv 6
1689 (emchat-v8-pack-dword status))
1690 (emchat-v8-pack-tlv 8
1691 (emchat-v8-pack-word 0)))))
1693 (defun emchat-v8-snac-cli-add-contact (ectx &optional contacts)
1694 "CLI_ADDCONTACT, SNAC(3,4)
1695 Send either CONTACTS or ECTX's contact list."
1697 (setq contacts (emchat-v8-ctx-get-prop ectx 'contacts)))
1698 (emchat-v8-debug "Adding contacts: %S" contacts)
1700 (emchat-v8-send ectx
1701 (emchat-v8-pack-snac ectx '(#x03 . #x04)
1702 (emchat-v8-pack-uinlist contacts)))))
1704 (defun emchat-v8-snac-cli-addvisible (ectx &optional uin-list)
1705 "CLI_ADDVISIBLE SNAC(9, 5)."
1707 (setq uin-list (emchat-v8-ctx-get-prop ectx 'visible-list)))
1708 (emchat-v8-debug "Adding to visible: %S" uin-list)
1710 (emchat-v8-send ectx
1711 (emchat-v8-pack-snac ectx '(#x09 . #x05)
1712 (emchat-v8-pack-uinlist uin-list)))))
1714 (defun emchat-v8-snac-cli-remvisible (ectx uin-list)
1715 "CLI_ADDVISIBLE SNAC(9, 6)."
1716 (emchat-v8-debug "Removing from visible: %S" uin-list)
1718 (emchat-v8-send ectx
1719 (emchat-v8-pack-snac ectx '(#x09 . #x06)
1720 (emchat-v8-pack-uinlist uin-list)))))
1722 (defun emchat-v8-snac-cli-addinvisible (ectx &optional uin-list)
1723 "CLI_ADDVISIBLE SNAC(9, 7)."
1725 (setq uin-list (emchat-v8-ctx-get-prop ectx 'invisible-list)))
1726 (emchat-v8-debug "Adding to invisible: %S" uin-list)
1728 (emchat-v8-send ectx
1729 (emchat-v8-pack-snac ectx '(#x09 . #x07)
1730 (emchat-v8-pack-uinlist uin-list)))))
1732 (defun emchat-v8-snac-cli-reminvisible (ectx uin-list)
1733 "CLI_REMINVISIBLE SNAC(9, 8)."
1734 (emchat-v8-debug "Removing from invisible: %S" uin-list)
1736 (emchat-v8-send ectx
1737 (emchat-v8-pack-snac ectx '(#x09 . #x08)
1738 (emchat-v8-pack-uinlist uin-list)))))
1740 (defun emchat-v8-snac-cli-keepalive (ectx)
1741 "Send keep-alive flap."
1742 (emchat-v8-send ectx
1743 (emchat-v8-pack-flap ectx 5)))
1745 (defun emchat-v8-pack-meta-snac (ectx sub &optional type &rest data)
1747 (setq data (apply 'concat data))
1749 (let ((seq3 (emchat-v8-ctx-get-prop ectx 'our-seq3))
1752 (emchat-v8-ctx-put-prop ectx 'our-seq3 (% (1+ seq3) 32767))
1753 (emchat-v8-ctx-put-prop ectx 'our-seq3 2))
1757 (emchat-v8-pack-uin (plist-get (emchat-v8-ctx-userinfo ectx) 'uin))
1758 (emchat-v8-number->string-swap 2 sub)
1759 (emchat-v8-number->string-swap 2 (emchat-v8-ctx-get-prop ectx 'our-seq3))
1761 (emchat-v8-number->string-swap 2 type))
1764 (emchat-v8-pack-snac ectx '(#x15 . #x02)
1765 (emchat-v8-pack-tlv 1
1766 (emchat-v8-number->string-swap 2 (length temp-data))
1769 (defun emchat-v8-snac-cli-reqofflinemsgs (ectx)
1770 "CLI_REQOFFLINEMSGS, SNAC(15,2)."
1771 (emchat-v8-send ectx
1772 (emchat-v8-pack-meta-snac ectx 60)))
1774 (defun emchat-v8-snac-cli-metareqinfo (ectx uin)
1775 "CLI_METAREQINFO, SNAC(15,2)/2000/1232."
1776 (emchat-v8-send ectx
1777 (emchat-v8-pack-meta-snac ectx 2000 1232
1778 (emchat-v8-pack-uin uin)))
1780 ;; Save pair SEQ/UIN for later UIN extraction
1781 (emchat-v8-ctx-put-prop ectx 'about-query-seq-uin
1782 (cons (cons (emchat-v8-ctx-get-prop ectx 'our-seq3) uin)
1783 (emchat-v8-ctx-get-prop ectx 'about-query-seq-uin))))
1785 (defun emchat-v8-snac-cli-searchbyuin (ectx uin)
1786 "CLI_SEARCHBYUIN, SNAC(15,2)/2000/1385."
1787 (emchat-v8-send ectx
1788 (emchat-v8-pack-meta-snac ectx 2000 1385
1789 (emchat-v8-pack-word-le 310) ; Search key (310 == uin)
1790 (emchat-v8-pack-lnts (emchat-v8-pack-uin uin)))))
1792 (defun emchat-v8-snac-cli-searchbyemail (ectx email)
1793 "CLI_SEARCHBYEMAIL, SNAC(15,2)/2000/1395."
1794 (emchat-v8-send ectx
1795 (emchat-v8-pack-meta-snac
1797 (emchat-v8-pack-word-le 350) ; Search key (350 == email)
1798 (emchat-v8-pack-llnts email))))
1800 (defun emchat-v8-snac-cli-searchbypersinf (ectx first last nick email online)
1801 "CLI_SEARCHBYPERSINF, SNAC(15,2)/2000/1375."
1802 (emchat-v8-send ectx
1803 (emchat-v8-pack-meta-snac
1805 (emchat-v8-pack-word-le 320) ; Search key (320 == first name)
1806 (emchat-v8-pack-llnts first)
1807 (emchat-v8-pack-word-le 330) ; Search key (330 == last name)
1808 (emchat-v8-pack-llnts last)
1809 (emchat-v8-pack-word-le 340) ; Search key (340 == nick name)
1810 (emchat-v8-pack-llnts nick)
1811 (emchat-v8-pack-word-le 350) ; Search key (350 == email)
1812 (emchat-v8-pack-llnts email)
1813 (emchat-v8-pack-byte online))))
1815 ;;; FIXME: this doesn't impliment direct connect or something called
1817 (defun emchat-v8-snac-cli-metasetsecurity (ectx auth web)
1818 "CLI_METASETSECURITY. SNAC(#x15, #x02)/2000/1060."
1819 (emchat-v8-send ectx
1820 (emchat-v8-pack-meta-snac
1822 (emchat-v8-pack-byte auth) ; req auth 0 = no; 1 = yes
1823 (emchat-v8-pack-byte web) ; webaware 0 = yes; 1 = no
1824 (emchat-v8-pack-byte #x02) ; dc hard coded to only with auth
1825 (emchat-v8-pack-byte 0)))) ; user kind (no idea, set to zero)
1827 (defun emchat-v8-snac-cli-ready (ectx)
1828 "CLI_READY, SNAC(1, 2)."
1829 (emchat-v8-send ectx
1830 (emchat-v8-pack-snac ectx '(#x01 . #x02)
1832 (mapcar #'(lambda (sn)
1834 (emchat-v8-pack-word (car sn))
1835 (emchat-v8-pack-word (cdr sn))
1837 (emchat-v8-pack-dword #x0101047B)
1838 (emchat-v8-pack-dword #x0110047B))))
1839 emchat-v8-snacv-list)))))
1841 (defun emchat-v8-snac-cli-families (ectx)
1842 "CLI_FAMILIES, SNAC(1, 17)."
1843 (emchat-v8-send ectx
1844 (emchat-v8-pack-snac ectx '(#x01 . #x17)
1846 (mapcar #'(lambda (sn)
1848 (emchat-v8-pack-word (car sn))
1849 (emchat-v8-pack-word (cdr sn))))
1850 emchat-v8-snacv-list)))))
1852 (defun emchat-v8-snac-cli-ratesrequest (ectx)
1853 "CLI_RATESREQUEST, SNAC(1, 6)."
1854 (emchat-v8-send ectx
1855 (emchat-v8-pack-snac ectx '(#x01 . #x06))))
1857 (defun emchat-v8-snac-cli-reqinfo (ectx)
1858 "CLI_REQINFO, SNAC(1, E)."
1859 (emchat-v8-send ectx
1860 (emchat-v8-pack-snac ectx '(#x01 . #x0E))))
1862 (defun emchat-v8-snac-cli-reqlocation (ectx)
1863 "CLI_REQLOCATION, SNAC(2, 2)."
1864 (emchat-v8-send ectx
1865 (emchat-v8-pack-snac ectx '(#x02 . #x02))))
1867 (defun emchat-v8-snac-cli-reqbuddy (ectx)
1868 "CLI_REQBUDDY, SNAC(3, 2)."
1869 (emchat-v8-send ectx
1870 (emchat-v8-pack-snac ectx '(#x03 . #x02))))
1872 (defun emchat-v8-snac-cli-reqicbm (ectx)
1873 "CLI_REQICBM, SNAC(4, 4)."
1874 (emchat-v8-send ectx
1875 (emchat-v8-pack-snac ectx '(#x04 . #x04))))
1877 (defun emchat-v8-snac-cli-sendmsg (ectx uin format msg)
1878 "CLI_SENDMSG, SNAC(4, 6).
1879 UIN - Icq uin to send message to.
1880 FORMAT - format id, 1 - simple, 2 - advanced, 4 - typed.
1881 MSG - Message itself."
1882 (emchat-v8-send ectx
1883 (emchat-v8-pack-snac ectx '(#x04 . #x06)
1884 (emchat-v8-pack-dword 0) ; random
1885 (emchat-v8-pack-dword 0) ; random
1886 (emchat-v8-pack-word format)
1887 (emchat-v8-pack-buin uin)
1889 (emchat-v8-pack-tlv 6))))
1891 (defconst emchat-v8-msg-encodings
1896 (defun emchat-v8-send-simple-message (ectx uin message)
1897 "Send simple message."
1898 (emchat-v8-snac-cli-sendmsg ectx uin 1
1899 (emchat-v8-pack-tlv 2
1900 (emchat-v8-pack-tlv 1281 (emchat-v8-pack-byte 1))
1901 (emchat-v8-pack-tlv 257
1902 (emchat-v8-pack-word 3)
1903 (emchat-v8-pack-word (+ 4 (length message)))
1906 (defun emchat-v8-send-typed-message (ectx uin type message)
1907 "Send typed message."
1908 (emchat-v8-snac-cli-sendmsg ectx uin 4
1909 (emchat-v8-pack-tlv 5
1910 (emchat-v8-pack-uin (plist-get (emchat-v8-ctx-userinfo ectx) 'uin))
1911 (emchat-v8-pack-word-le
1912 (car (find type emchat-v8-msg-types :key 'cdr :test 'eq)))
1913 (emchat-v8-pack-lnts message))))
1915 (defun emchat-v8-send-advanced-message (ectx uin &rest add-arguments-here-for-advanced-message)
1916 ;; Advanced message:
1918 ;; 2 ACKTYPE : 0 - normal, 1 - abort, 2 - file ack
1921 ;; TLV(11) UNKNOWN : Only if ACTYPE is 1
1923 ;; TLV(10) ACKTYPE2 : 1 - normal, 2 - file ack
1927 ;; TLV(1001) MESSAGE
1928 ; (emchat-v8-snac-cli-sendmsg ectx uin 2)
1929 (emchat-v8-debug "TODO: `emchat-v8-send-advanced-message'")
1932 (defun emchat-v8-send-server-message (ectx uin &rest add-arguments-here-for-server-message)
1935 ;; 4 UIN : sender uin
1936 ;; 2 MSGTYPE : message type
1937 ;; LNTS MSG : message with unspecified encoding
1938 ; (emchat-v8-snac-cli-sendmsg ectx uin 3)
1939 (emchat-v8-debug "TODO: `emchat-v8-send-advanced-message'")
1942 (defun emchat-v8-snac-cli-reqbos (ectx)
1943 "CLI_REQBOS, SNAC(9, 2)."
1944 (emchat-v8-send ectx
1945 (emchat-v8-pack-snac ectx '(#x09 . #x02))))
1947 (defun emchat-v8-handle-flap (ectx-flap)
1948 (let* ((ectx (car ectx-flap))
1949 (flap (cdr ectx-flap))
1950 (cid (emchat-v8-flap-cid flap)))
1951 (cond ((= cid emchat-v8-FLAP-HELLO)
1952 ;; XXX Login channel
1953 (emchat-v8-debug "Got HELLO cid")
1954 (let ((cmd (emchat-v8-fetch-dword (emchat-v8-flap-data flap)))
1955 (cli-cook (emchat-v8-ctx-get-prop ectx 'cli-cookie)))
1958 ;; Already logged in, send Cookie
1959 (emchat-v8-send ectx
1960 (emchat-v8-pack-flap ectx emchat-v8-FLAP-HELLO
1961 (emchat-v8-pack-dword 1)
1962 (emchat-v8-pack-tlv 6 cli-cook)))
1964 ;; Not logged in yet
1965 (emchat-v8-login ectx)))
1967 (t (error (format "Unknown FLAP CMD(%) in login channel." cmd))))
1970 ((= cid emchat-v8-FLAP-SNAC)
1974 (let ((snac (emchat-v8-fetch-snac (emchat-v8-flap-data flap)))
1975 (snacs emchat-v8-snac-list))
1977 (or (not (= (emchat-v8-snac-family snac)
1978 (car (caar snacs))))
1979 (not (= (emchat-v8-snac-subtype snac)
1980 (cdr (caar snacs))))))
1981 (setq snacs (cdr snacs)))
1983 (emchat-v8-debug "SNAC %S (%S)" snac (when (car snacs) (nth 1 (car snacs))))
1986 (error 'invalid-argument "Unknown SNAC" snac))
1988 ;; Call snac handler
1989 (funcall (nth 2 (car snacs))
1991 (emchat-v8-flap-data flap) ; data
1992 (emchat-v8-snac-flags snac)))) ; snac flags
1994 ((= cid emchat-v8-FLAP-ERRORS)
1996 (emchat-v8-debug "ERROR")
1999 ((= cid emchat-v8-FLAP-LOGOFF)
2001 (let* ((tlvs (emchat-v8-fetch-tlvs (emchat-v8-flap-data flap)))
2002 (tlv (emchat-v8-tlv-get tlvs 5)))
2004 (emchat-v8-debug "LOGOFF tlv_t5=%S" tlv)
2006 (emchat-v8-close ectx)
2009 ;; Another user with same UIN
2010 (emchat-v8-ctx-run-incoming-handler ectx 'logoff)
2013 (let* ((nsrv (split-string (emchat-v8-tlv-str tlv) ":"))
2015 (port (string-to-int (nth 1 nsrv))))
2016 (emchat-v8-debug "Redirected to new server: %s:%d" addr port)
2017 ;; Store cookie and reconnect
2018 (emchat-v8-ctx-put-prop ectx 'cli-cookie
2019 (emchat-v8-tlv-str (emchat-v8-tlv-get tlvs 6)))
2020 (emchat-v8-connect ectx addr port)))))
2022 ((= cid emchat-v8-FLAP-PING)
2024 (emchat-v8-debug "PING")
2027 (t (error (format "Unknown FLAP cid(%d)." cid))))
2030 (defun emchat-v8-fetch-handle-flaps (ectx)
2031 (while (> (length (emchat-v8-ctx-incoming-buffer ectx)) 0)
2032 ;; Do not do anything in filter function
2033 (emchat-v8-handle-flap (cons ectx (emchat-v8-fetch-flap ectx)))))
2036 (defun emchat-v8-number->string (size val)
2037 "Convert number value VAL to string of SIZE."
2039 (setq val (truncate val))
2040 (char-to-string val))
2042 (setq val (truncate val))
2043 (concat (char-to-string (ash (mod val 65536) -8))
2044 (char-to-string (logand val 255))
2048 (setq val (truncate val))
2049 (mapconcat 'identity
2051 (list (char-to-string (int-to-char (% val 256)))
2052 (char-to-string (int-to-char (% (setq val (/ val 256)) 256)))
2053 (char-to-string (int-to-char (% (setq val (/ val 256)) 256)))
2054 (char-to-string (int-to-char (% (setq val (/ val 256)) 256)))
2058 (t (error "Invalid SIZE" size))))
2060 (defun emchat-v8-number->string-swap (size val)
2061 "Convert number VAL to string of SIZE."
2062 (let ((ss (emchat-v8-number->string size val))
2065 (setq tt (aref ss 0))
2066 (aset ss 0 (aref ss 1))
2069 (setq tt (aref ss 0))
2070 (aset ss 0 (aref ss 3))
2072 (setq tt (aref ss 1))
2073 (aset ss 1 (aref ss 2))
2077 (defun emchat-v8-create-message (&rest UNIPREFIX-message-spec)
2078 "Create emchat message according to SPEC."
2079 (let (UNIPREFIX-value-spec UNIPREFIX-value)
2080 (mapconcat (lambda (UNIPREFIX-element)
2081 (setq UNIPREFIX-value-spec (eval (aref UNIPREFIX-element 0)))
2082 (setq UNIPREFIX-value (eval (aref UNIPREFIX-element 1)))
2084 (cond ((numberp UNIPREFIX-value)
2085 (emchat-v8-number->string UNIPREFIX-value-spec UNIPREFIX-value))
2086 ((stringp UNIPREFIX-value)
2087 (substring UNIPREFIX-value 0 UNIPREFIX-value-spec))
2088 ((null UNIPREFIX-value)
2089 (make-string UNIPREFIX-value-spec ?\x00))
2090 (t (error "Invalid SPEC" UNIPREFIX-value-spec))))
2091 UNIPREFIX-message-spec "")
2094 (defun emchat-v8-string->number-le-flt (str &optional len)
2095 "Convert STR to number."
2097 (setq len (length str)))
2099 (let ((ret 0.0) (i 0))
2101 (setq ret (+ ret (* (char-int (aref str i)) (expt 256.0 i)))
2105 (defun emchat-v8-string->number-flt (str &optional len)
2106 "Convert STR to number."
2108 (setq len (length str)))
2110 (let ((ret 0.0) (i 0))
2112 (setq ret (+ (* 256.0 ret) (char-int (aref str i)))
2116 (defun emchat-v8-string->number-le-bigz (str &optional len)
2117 "Convert STR to number."
2118 ;; optimise for common cases
2120 (+ (* (aref str 3) 16777216)
2121 (* (aref str 2) 65536)
2122 (* (aref str 1) 256)
2125 (+ (* (aref str 1) 256)
2128 (char-to-int (aref str 0)))
2130 (let* ((len (or len (length str)))
2131 (ret (char-int (aref str 0)))
2134 (setq ret (+ ret (* (char-int (aref str i))
2139 (defun emchat-v8-string->number-bigz (str &optional len)
2140 "Convert STR to number."
2141 ;; optimise for common cases
2143 (+ (* (aref str 0) 16777216)
2144 (* (aref str 1) 65536)
2145 (* (aref str 2) 256)
2148 (+ (* (aref str 0) 256)
2151 (char-to-int (aref str 0)))
2153 (let* ((len (or len (length str)))
2157 (setq ret (+ (lsh ret 8) (char-int (aref str i)))
2161 ;; do the right thing at the right time, the wrong otherwise
2164 (defalias #'emchat-v8-string->number #'emchat-v8-string->number-bigz)
2165 (defalias #'emchat-v8-string->number-le #'emchat-v8-string->number-le-bigz)
2168 (defalias #'emchat-v8-string->number #'emchat-v8-string->number-flt)
2169 (defalias #'emchat-v8-string->number-le #'emchat-v8-string->number-le-flt)
2172 (defvar emchat-v8-timeout 15
2173 "Receive timeout in seconds.")
2175 (defun emchat-v8-grab-bytes (ectx len)
2176 "Grab LEN bytes from ECTX's incoming buffer."
2177 (setq len (truncate len)) ;for sure
2180 (while (< (length (emchat-v8-ctx-incoming-buffer ectx)) len)
2181 (when (null (accept-process-output (emchat-v8-ctx-proc ectx)
2183 (error "EMCHAT: Timeout")))
2184 (setq rstr (substring (emchat-v8-ctx-incoming-buffer ectx) 0 len))
2185 (setf (emchat-v8-ctx-incoming-buffer ectx)
2186 (substring (emchat-v8-ctx-incoming-buffer ectx) len))
2189 (defun emchat-v8-grab-bytes-1 (vmsg len)
2190 "Grab LEN bytes from VMSG."
2191 (setq len (truncate len))
2195 (when (> len (length (aref vmsg 0)))
2196 (error 'invalid-argument "Invalid len" len))
2198 (setq rstr (substring (aref vmsg 0) 0 len))
2199 (aset vmsg 0 (substring (aref vmsg 0) len))
2202 ;; Generic length storers
2203 (defvar emchat-v8-length-1 nil)
2204 (defvar emchat-v8-length-2 nil)
2205 (defvar emchat-v8-length-3 nil)
2206 (defvar emchat-v8-length-4 nil)
2208 (defun emchat-v8-parse-message (ectx-msg spec)
2209 "Parse ECTX-MSG according to SPEC.
2210 ECTX-MSG is either EMchat context to grab bytes from, or string.
2213 - Vector specifies one value.
2214 - List specifies multiple values.
2215 - List of Lists specifies list of lists of multiple values."
2216 (when (stringp ectx-msg)
2217 (setq ectx-msg (vector ectx-msg)))
2219 (let ((accessor (if (emchat-v8-ctx-p ectx-msg) 'emchat-v8-grab-bytes 'emchat-v8-grab-bytes-1))
2222 (cond ((vectorp spec)
2224 (setq vlen (truncate (eval (aref spec 0))))
2225 (setq vtype (aref spec 1))
2227 (when (not (= (emchat-v8-string->number (funcall accessor ectx-msg vlen) vlen)
2229 (error 'invalid-argument "Invalid argument in MSG"))
2232 (cond ((or (eq vtype 'number) (eq vtype 'integer))
2233 (setq rlist (emchat-v8-string->number (funcall accessor ectx-msg vlen) vlen)))
2235 ((or (eq vtype 'number-swap) (eq vtype 'integer-swap))
2236 (setq rlist (emchat-v8-string->number-le (funcall accessor ectx-msg vlen) vlen)))
2239 (setq rlist (funcall accessor ectx-msg vlen)))
2241 ((and (symbolp vtype) (not (keywordp vtype))
2242 (member vtype '(emchat-v8-length-1 emchat-v8-length-2 emchat-v8-length-3 emchat-v8-length-4)))
2243 ;; If symbol - set it
2244 (set vtype (emchat-v8-string->number (funcall accessor ectx-msg vlen) vlen))
2245 (setq rlist (symbol-value vtype)))
2248 (setq rlist (mapcar #'(lambda (not-used)
2249 (emchat-v8-parse-message ectx-msg vtype))
2250 (make-list vlen nil))))
2252 ((null vtype) ;; Skip
2255 (t (error 'invalid-argument "Invalid type in SPEC" vtype)))))
2258 (not (member nil (mapcar (lambda (l) (listp l)) spec))))
2264 (setq rlist (mapcar (lambda (e) (emchat-v8-parse-message ectx-msg e)) spec)))
2266 (t (error 'invalid-argument "Invalid SPEC" spec)))
2271 (put 'emchat-v8-parse-message 'lisp-indent-function 1)
2273 (defun emchat-v8-fetch-data (data len)
2274 (vector (funcall (if (emchat-v8-ctx-p data)
2275 'emchat-v8-grab-bytes
2276 'emchat-v8-grab-bytes-1)
2279 (defun emchat-v8-fetch-string (data &optional len)
2280 (aref (emchat-v8-fetch-data data (or len (length (aref data 0)))) 0))
2282 (defun emchat-v8-fetch-byte (data)
2283 (char-to-int (string-to-char (emchat-v8-fetch-string data 1))))
2284 (defun emchat-v8-pack-byte (byte)
2285 (char-to-string byte))
2287 (defun emchat-v8-fetch-word (data)
2288 (truncate (emchat-v8-string->number
2289 (emchat-v8-fetch-string data 2))))
2290 (defun emchat-v8-pack-word (word)
2291 (emchat-v8-number->string 2 word))
2293 (defun emchat-v8-fetch-word-le (data)
2294 (truncate (emchat-v8-string->number-le
2295 (emchat-v8-fetch-string data 2))))
2296 (defun emchat-v8-pack-word-le (word)
2297 (emchat-v8-number->string-swap 2 word))
2299 (defun emchat-v8-fetch-dword (data)
2300 (emchat-v8-string->number
2301 (emchat-v8-fetch-string data 4)))
2302 (defun emchat-v8-pack-dword (dword)
2303 (emchat-v8-number->string 4 dword))
2305 (defun emchat-v8-fetch-time (data)
2306 (cons (emchat-v8-fetch-word data)
2307 (emchat-v8-fetch-word data)))
2309 (defun emchat-v8-pack-time (time)
2311 (emchat-v8-pack-word (car time))
2312 (emchat-v8-pack-word (cdr time))))
2314 (defun emchat-v8-fetch-uin (data)
2316 (emchat-v8-string->number-le
2317 (emchat-v8-fetch-string data 4))))
2319 (defun emchat-v8-fetch-uinlist (count uinlist)
2322 (append (emchat-v8-fetch-uin uinlist) result))))
2324 (defun emchat-v8-pack-uin (uin)
2325 (emchat-v8-number->string-swap 4 uin))
2327 (defun emchat-v8-fetch-buin (data)
2328 "Fetch BUIN and return uin number."
2329 (string-to-number (emchat-v8-fetch-string data (emchat-v8-fetch-byte data))))
2330 (defun emchat-v8-pack-buin (uin)
2331 (let ((suin (number-to-string uin)))
2332 (concat (emchat-v8-pack-byte (length suin)) suin)))
2334 (defun emchat-v8-fetch-bstr (data)
2335 (let* ((len (emchat-v8-fetch-word data))
2336 (str (emchat-v8-fetch-string data len)))
2337 (substring str 0 len)))
2339 (defun emchat-v8-pack-bstr (str)
2340 (concat (emchat-v8-pack-word (length str)) str))
2343 (defun emchat-v8-pack-uinlist (uin-list)
2344 (apply 'concat (mapcar 'emchat-v8-pack-buin uin-list)))
2346 (defun emchat-v8-pack-nts (string)
2347 (concat string (char-to-string 0)))
2349 (defun emchat-v8-pack-lnts (string)
2350 (let ((nts (emchat-v8-pack-nts string)))
2352 (emchat-v8-pack-word-le (length nts))
2355 (defun emchat-v8-pack-llnts (string)
2356 (let ((nts (emchat-v8-pack-nts string)))
2358 (emchat-v8-pack-word-le (+ (length nts) 2))
2359 (emchat-v8-pack-word-le (length nts))
2362 (defun emchat-v8-fetch-lnts (data)
2363 (let* ((len (emchat-v8-fetch-word-le data))
2364 (str (emchat-v8-fetch-string data len)))
2365 (substring str 0 (1- len))))
2368 (defun emchat-v8-fetch-flap (data)
2369 "Get next queued FLAP from emchat context ECTX."
2371 (emchat-v8-ctx-proc data) 'emchat-v8-proc-filter-accumulator)
2375 (let ((bb (emchat-v8-fetch-byte data)))
2377 (error "Unexpected data while fetching FLAP")))
2379 (let* ((cin (emchat-v8-fetch-byte data))
2380 (seq (emchat-v8-fetch-word data))
2381 (flen (emchat-v8-fetch-word data))
2382 (fdata (emchat-v8-fetch-data data flen)))
2383 (list cin seq fdata)))
2386 (emchat-v8-ctx-proc data) 'emchat-v8-proc-filter-proccessing)))
2388 (defun emchat-v8-pack-flap (ectx chan-id &rest flap-data)
2389 "Create FLAP packet of channel id CHAN-ID and DATA."
2390 (setq flap-data (apply 'concat flap-data))
2394 (emchat-v8-pack-byte #x2A)
2395 (emchat-v8-pack-byte chan-id)
2396 (emchat-v8-pack-word (emchat-v8-ctx-sequence ectx))
2397 (emchat-v8-pack-word (length flap-data))
2400 ;; Increase sequence number
2401 (incf (emchat-v8-ctx-sequence ectx))
2402 (when (> (emchat-v8-ctx-sequence ectx) 65535)
2403 (setf (emchat-v8-ctx-sequence ectx)
2404 (% (emchat-v8-ctx-sequence ectx) 65536)))))
2405 (put 'emchat-v8-pack-flap 'lisp-indent-function 2)
2408 (defun emchat-v8-fetch-snac (data)
2410 (let ((family (emchat-v8-fetch-word data))
2411 (subtype (emchat-v8-fetch-word data))
2412 (flags (emchat-v8-fetch-word data))
2413 (rid (emchat-v8-fetch-dword data)))
2415 ;; If 15th bit is set in FLAGS then DATA contains some additional
2416 ;; data in format LENGTH [WORD], DATA [LENGTH]
2417 (unless (zerop (logand flags 32768))
2418 (let ((len (emchat-v8-fetch-word data)))
2419 (emchat-v8-fetch-data data len)))
2421 (list family subtype flags rid)))
2423 (defun emchat-v8-pack-snac (ectx family-subtype &rest snac-data)
2424 "Create SNAC packet."
2425 (setq snac-data (apply 'concat snac-data))
2426 (emchat-v8-pack-flap ectx 2
2427 (emchat-v8-pack-word (car family-subtype))
2428 (emchat-v8-pack-word (cdr family-subtype))
2429 (emchat-v8-pack-word 0) ; XXX flags
2430 (emchat-v8-pack-dword 0) ; XXX rid
2432 (put 'emchat-v8-pack-snac 'lisp-indent-function 2)
2435 (defun emchat-v8-fetch-single-tlv (data)
2436 (let* ((type (emchat-v8-fetch-word data))
2437 (len (emchat-v8-fetch-word data))
2438 (value (emchat-v8-fetch-data data len)))
2439 (list type len value)))
2441 (defun emchat-v8-fetch-tlvs (data)
2442 "From VMSG extract TLV list."
2444 (while (> (length (aref data 0)) 0)
2445 (setq tlvs (cons (emchat-v8-fetch-single-tlv data) tlvs)))
2448 (defun emchat-v8-fetch-n-tlvs (data n)
2449 "Read TLVs of total length N and return a list."
2452 (let* ((tlv (emchat-v8-fetch-single-tlv data)))
2453 (setq n (- n (emchat-v8-tlv-len tlv) 4)
2454 tlvs (cons tlv tlvs))))
2457 (defun emchat-v8-tlv-get (tlv-list type)
2458 "From TLV list TLV-LIST get tlv of TYPE."
2459 (while (and tlv-list (not (= (emchat-v8-tlv-type (car tlv-list)) type)))
2460 (setq tlv-list (cdr tlv-list)))
2463 (defun emchat-v8-pack-tlv (type &rest values)
2465 (let ((val (apply 'concat values)))
2467 (emchat-v8-pack-word type)
2468 (emchat-v8-pack-word (length val))
2470 (put 'emchat-v8-pack-tlv 'lisp-indent-function 1)
2473 (defun emchat-v8-login (ectx &optional uin password)
2474 "In ECTX context send UIN/PASSWORD to ICQ server."
2475 (emchat-v8-debug "Logging in ..")
2478 (setq uin (plist-get (emchat-v8-ctx-userinfo ectx) 'uin)))
2480 (setq password (plist-get (emchat-v8-ctx-userinfo ectx) 'password)))
2482 ;; Remove password (for somekind of security)
2483 (setf (emchat-v8-ctx-userinfo ectx)
2484 (plist-remprop (emchat-v8-ctx-userinfo ectx) 'password))
2486 (emchat-v8-send ectx
2487 (emchat-v8-pack-flap ectx emchat-v8-FLAP-HELLO
2488 (emchat-v8-pack-dword 1)
2489 (emchat-v8-pack-tlv 1
2490 (number-to-string uin))
2491 (emchat-v8-pack-tlv 2 (emchat-v8-util-encrypt password))
2492 (emchat-v8-pack-tlv 3 emchat-v8-client-id-string)
2493 (emchat-v8-pack-tlv #x16
2494 (emchat-v8-pack-word #x010A))
2495 (emchat-v8-pack-tlv #x17
2496 (emchat-v8-pack-word emchat-v8-FLAP-VER-MAJOR))
2497 (emchat-v8-pack-tlv #x18
2498 (emchat-v8-pack-word emchat-v8-FLAP-VER-MINOR))
2499 (emchat-v8-pack-tlv #x19
2500 (emchat-v8-pack-word emchat-v8-FLAP-VER-LESSER))
2501 (emchat-v8-pack-tlv #x1A
2502 (emchat-v8-pack-word emchat-v8-FLAP-VER-BUILD))
2503 (emchat-v8-pack-tlv #x14
2504 (emchat-v8-pack-dword emchat-v8-FLAP-VER-SUBBUILD))
2505 (emchat-v8-pack-tlv #x0F "en")
2506 (emchat-v8-pack-tlv #x0E "us"))))
2509 (provide 'emchat-v8)
2511 ;;; emchat-v8.el ends here