emacs-jabber-0.8.0/0000777000175100017510000000000011252722243011041 500000000000000emacs-jabber-0.8.0/compat/0000777000175100017510000000000011252722242012323 500000000000000emacs-jabber-0.8.0/compat/sha1.el0000644000175100017510000003717611133727374013444 00000000000000;;; sha1.el --- SHA1 Secure Hash Algorithm in Emacs-Lisp ;; Copyright (C) 1999, 2001, 2002, 2003, 2004, ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ;; Author: Shuhei KOBAYASHI ;; Keywords: SHA1, FIPS 180-1 ;; This file is part of FLIM (Faithful Library about Internet Message). ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 3, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This program is implemented from the definition of SHA-1 in FIPS PUB ;; 180-1 (Federal Information Processing Standards Publication 180-1), ;; "Announcing the Standard for SECURE HASH STANDARD". ;; ;; (EXCEPTION; two optimizations taken from GnuPG/cipher/sha1.c) ;; ;; Test cases from FIPS PUB 180-1. ;; ;; (sha1 "abc") ;; => a9993e364706816aba3e25717850c26c9cd0d89d ;; ;; (sha1 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") ;; => 84983e441c3bd26ebaae4aa1f95129e5e54670f1 ;; ;; (sha1 (make-string 1000000 ?a)) ;; => 34aa973cd4c4daa4f61eeb2bdbad27316534016f ;; ;; BUGS: ;; * It is assumed that length of input string is less than 2^29 bytes. ;; * It is caller's responsibility to make string (or region) unibyte. ;; ;; TODO: ;; * Rewrite from scratch! ;; This version is much faster than Keiichi Suzuki's another sha1.el, ;; but it is too dirty. ;;; Code: (require 'hex-util) ;;; ;;; external SHA1 function. ;;; (defgroup sha1 nil "Elisp interface for SHA1 hash computation." :version "22.1" :group 'extensions) (defcustom sha1-maximum-internal-length 500 "*Maximum length of message to use Lisp version of SHA1 function. If message is longer than this, `sha1-program' is used instead. If this variable is set to 0, use external program only. If this variable is set to nil, use internal function only." :type 'integer :group 'sha1) (defcustom sha1-program '("sha1sum") "*Name of program to compute SHA1. It must be a string \(program name\) or list of strings \(name and its args\)." :type '(repeat string) :group 'sha1) (defcustom sha1-use-external (condition-case () (executable-find (car sha1-program)) (error)) "*Use external SHA1 program. If this variable is set to nil, use internal function only." :type 'boolean :group 'sha1) (defun sha1-string-external (string &optional binary) (let (prog args digest default-enable-multibyte-characters) (if (consp sha1-program) (setq prog (car sha1-program) args (cdr sha1-program)) (setq prog sha1-program args nil)) (with-temp-buffer (insert string) (apply (function call-process-region) (point-min)(point-max) prog t t nil args) ;; SHA1 is 40 bytes long in hexadecimal form. (setq digest (buffer-substring (point-min)(+ (point-min) 40)))) (if binary (decode-hex-string digest) digest))) (defun sha1-region-external (beg end &optional binary) (sha1-string-external (buffer-substring-no-properties beg end) binary)) ;;; ;;; internal SHA1 function. ;;; (eval-when-compile ;; optional second arg of string-to-number is new in v20. (defconst sha1-K0-high 23170) ; (string-to-number "5A82" 16) (defconst sha1-K0-low 31129) ; (string-to-number "7999" 16) (defconst sha1-K1-high 28377) ; (string-to-number "6ED9" 16) (defconst sha1-K1-low 60321) ; (string-to-number "EBA1" 16) (defconst sha1-K2-high 36635) ; (string-to-number "8F1B" 16) (defconst sha1-K2-low 48348) ; (string-to-number "BCDC" 16) (defconst sha1-K3-high 51810) ; (string-to-number "CA62" 16) (defconst sha1-K3-low 49622) ; (string-to-number "C1D6" 16) ;; original definition of sha1-F0. ;; (defmacro sha1-F0 (B C D) ;; (` (logior (logand (, B) (, C)) ;; (logand (lognot (, B)) (, D))))) ;; a little optimization from GnuPG/cipher/sha1.c. (defmacro sha1-F0 (B C D) `(logxor ,D (logand ,B (logxor ,C ,D)))) (defmacro sha1-F1 (B C D) `(logxor ,B ,C ,D)) ;; original definition of sha1-F2. ;; (defmacro sha1-F2 (B C D) ;; (` (logior (logand (, B) (, C)) ;; (logand (, B) (, D)) ;; (logand (, C) (, D))))) ;; a little optimization from GnuPG/cipher/sha1.c. (defmacro sha1-F2 (B C D) `(logior (logand ,B ,C) (logand ,D (logior ,B ,C)))) (defmacro sha1-F3 (B C D) `(logxor ,B ,C ,D)) (defmacro sha1-S1 (W-high W-low) `(let ((W-high ,W-high) (W-low ,W-low)) (setq S1W-high (+ (% (* W-high 2) 65536) (/ W-low ,(/ 65536 2)))) (setq S1W-low (+ (/ W-high ,(/ 65536 2)) (% (* W-low 2) 65536))))) (defmacro sha1-S5 (A-high A-low) `(progn (setq S5A-high (+ (% (* ,A-high 32) 65536) (/ ,A-low ,(/ 65536 32)))) (setq S5A-low (+ (/ ,A-high ,(/ 65536 32)) (% (* ,A-low 32) 65536))))) (defmacro sha1-S30 (B-high B-low) `(progn (setq S30B-high (+ (/ ,B-high 4) (* (% ,B-low 4) ,(/ 65536 4)))) (setq S30B-low (+ (/ ,B-low 4) (* (% ,B-high 4) ,(/ 65536 4)))))) (defmacro sha1-OP (round) `(progn (sha1-S5 sha1-A-high sha1-A-low) (sha1-S30 sha1-B-high sha1-B-low) (setq sha1-A-low (+ (,(intern (format "sha1-F%d" round)) sha1-B-low sha1-C-low sha1-D-low) sha1-E-low ,(symbol-value (intern (format "sha1-K%d-low" round))) (aref block-low idx) (progn (setq sha1-E-low sha1-D-low) (setq sha1-D-low sha1-C-low) (setq sha1-C-low S30B-low) (setq sha1-B-low sha1-A-low) S5A-low))) (setq carry (/ sha1-A-low 65536)) (setq sha1-A-low (% sha1-A-low 65536)) (setq sha1-A-high (% (+ (,(intern (format "sha1-F%d" round)) sha1-B-high sha1-C-high sha1-D-high) sha1-E-high ,(symbol-value (intern (format "sha1-K%d-high" round))) (aref block-high idx) (progn (setq sha1-E-high sha1-D-high) (setq sha1-D-high sha1-C-high) (setq sha1-C-high S30B-high) (setq sha1-B-high sha1-A-high) S5A-high) carry) 65536)))) (defmacro sha1-add-to-H (H X) `(progn (setq ,(intern (format "sha1-%s-low" H)) (+ ,(intern (format "sha1-%s-low" H)) ,(intern (format "sha1-%s-low" X)))) (setq carry (/ ,(intern (format "sha1-%s-low" H)) 65536)) (setq ,(intern (format "sha1-%s-low" H)) (% ,(intern (format "sha1-%s-low" H)) 65536)) (setq ,(intern (format "sha1-%s-high" H)) (% (+ ,(intern (format "sha1-%s-high" H)) ,(intern (format "sha1-%s-high" X)) carry) 65536)))) ) ;;; buffers (H0 H1 H2 H3 H4). (defvar sha1-H0-high) (defvar sha1-H0-low) (defvar sha1-H1-high) (defvar sha1-H1-low) (defvar sha1-H2-high) (defvar sha1-H2-low) (defvar sha1-H3-high) (defvar sha1-H3-low) (defvar sha1-H4-high) (defvar sha1-H4-low) (defun sha1-block (block-high block-low) (let (;; step (c) --- initialize buffers (A B C D E). (sha1-A-high sha1-H0-high) (sha1-A-low sha1-H0-low) (sha1-B-high sha1-H1-high) (sha1-B-low sha1-H1-low) (sha1-C-high sha1-H2-high) (sha1-C-low sha1-H2-low) (sha1-D-high sha1-H3-high) (sha1-D-low sha1-H3-low) (sha1-E-high sha1-H4-high) (sha1-E-low sha1-H4-low) (idx 16)) ;; step (b). (let (;; temporary variables used in sha1-S1 macro. S1W-high S1W-low) (while (< idx 80) (sha1-S1 (logxor (aref block-high (- idx 3)) (aref block-high (- idx 8)) (aref block-high (- idx 14)) (aref block-high (- idx 16))) (logxor (aref block-low (- idx 3)) (aref block-low (- idx 8)) (aref block-low (- idx 14)) (aref block-low (- idx 16)))) (aset block-high idx S1W-high) (aset block-low idx S1W-low) (setq idx (1+ idx)))) ;; step (d). (setq idx 0) (let (;; temporary variables used in sha1-OP macro. S5A-high S5A-low S30B-high S30B-low carry) (while (< idx 20) (sha1-OP 0) (setq idx (1+ idx))) (while (< idx 40) (sha1-OP 1) (setq idx (1+ idx))) (while (< idx 60) (sha1-OP 2) (setq idx (1+ idx))) (while (< idx 80) (sha1-OP 3) (setq idx (1+ idx)))) ;; step (e). (let (;; temporary variables used in sha1-add-to-H macro. carry) (sha1-add-to-H H0 A) (sha1-add-to-H H1 B) (sha1-add-to-H H2 C) (sha1-add-to-H H3 D) (sha1-add-to-H H4 E)))) (defun sha1-binary (string) "Return the SHA1 of STRING in binary form." (let (;; prepare buffers for a block. byte-length of block is 64. ;; input block is split into two vectors. ;; ;; input block: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ... ;; block-high: +-0-+ +-1-+ +-2-+ +-3-+ ;; block-low: +-0-+ +-1-+ +-2-+ +-3-+ ;; ;; length of each vector is 80, and elements of each vector are ;; 16bit integers. elements 0x10-0x4F of each vector are ;; assigned later in `sha1-block'. (block-high (eval-when-compile (make-vector 80 nil))) (block-low (eval-when-compile (make-vector 80 nil)))) (unwind-protect (let* (;; byte-length of input string. (len (length string)) (lim (* (/ len 64) 64)) (rem (% len 4)) (idx 0)(pos 0)) ;; initialize buffers (H0 H1 H2 H3 H4). (setq sha1-H0-high 26437 ; (string-to-number "6745" 16) sha1-H0-low 8961 ; (string-to-number "2301" 16) sha1-H1-high 61389 ; (string-to-number "EFCD" 16) sha1-H1-low 43913 ; (string-to-number "AB89" 16) sha1-H2-high 39098 ; (string-to-number "98BA" 16) sha1-H2-low 56574 ; (string-to-number "DCFE" 16) sha1-H3-high 4146 ; (string-to-number "1032" 16) sha1-H3-low 21622 ; (string-to-number "5476" 16) sha1-H4-high 50130 ; (string-to-number "C3D2" 16) sha1-H4-low 57840) ; (string-to-number "E1F0" 16) ;; loop for each 64 bytes block. (while (< pos lim) ;; step (a). (setq idx 0) (while (< idx 16) (aset block-high idx (+ (* (aref string pos) 256) (aref string (1+ pos)))) (setq pos (+ pos 2)) (aset block-low idx (+ (* (aref string pos) 256) (aref string (1+ pos)))) (setq pos (+ pos 2)) (setq idx (1+ idx))) (sha1-block block-high block-low)) ;; last block. (if (prog1 (< (- len lim) 56) (setq lim (- len rem)) (setq idx 0) (while (< pos lim) (aset block-high idx (+ (* (aref string pos) 256) (aref string (1+ pos)))) (setq pos (+ pos 2)) (aset block-low idx (+ (* (aref string pos) 256) (aref string (1+ pos)))) (setq pos (+ pos 2)) (setq idx (1+ idx))) ;; this is the last (at most) 32bit word. (cond ((= rem 3) (aset block-high idx (+ (* (aref string pos) 256) (aref string (1+ pos)))) (setq pos (+ pos 2)) (aset block-low idx (+ (* (aref string pos) 256) 128))) ((= rem 2) (aset block-high idx (+ (* (aref string pos) 256) (aref string (1+ pos)))) (aset block-low idx 32768)) ((= rem 1) (aset block-high idx (+ (* (aref string pos) 256) 128)) (aset block-low idx 0)) (t ;; (= rem 0) (aset block-high idx 32768) (aset block-low idx 0))) (setq idx (1+ idx)) (while (< idx 16) (aset block-high idx 0) (aset block-low idx 0) (setq idx (1+ idx)))) ;; last block has enough room to write the length of string. (progn ;; write bit length of string to last 4 bytes of the block. (aset block-low 15 (* (% len 8192) 8)) (setq len (/ len 8192)) (aset block-high 15 (% len 65536)) ;; XXX: It is not practical to compute SHA1 of ;; such a huge message on emacs. ;; (setq len (/ len 65536)) ; for 64bit emacs. ;; (aset block-low 14 (% len 65536)) ;; (aset block-high 14 (/ len 65536)) (sha1-block block-high block-low)) ;; need one more block. (sha1-block block-high block-low) (fillarray block-high 0) (fillarray block-low 0) ;; write bit length of string to last 4 bytes of the block. (aset block-low 15 (* (% len 8192) 8)) (setq len (/ len 8192)) (aset block-high 15 (% len 65536)) ;; XXX: It is not practical to compute SHA1 of ;; such a huge message on emacs. ;; (setq len (/ len 65536)) ; for 64bit emacs. ;; (aset block-low 14 (% len 65536)) ;; (aset block-high 14 (/ len 65536)) (sha1-block block-high block-low)) ;; make output string (in binary form). (let ((result (make-string 20 0))) (aset result 0 (/ sha1-H0-high 256)) (aset result 1 (% sha1-H0-high 256)) (aset result 2 (/ sha1-H0-low 256)) (aset result 3 (% sha1-H0-low 256)) (aset result 4 (/ sha1-H1-high 256)) (aset result 5 (% sha1-H1-high 256)) (aset result 6 (/ sha1-H1-low 256)) (aset result 7 (% sha1-H1-low 256)) (aset result 8 (/ sha1-H2-high 256)) (aset result 9 (% sha1-H2-high 256)) (aset result 10 (/ sha1-H2-low 256)) (aset result 11 (% sha1-H2-low 256)) (aset result 12 (/ sha1-H3-high 256)) (aset result 13 (% sha1-H3-high 256)) (aset result 14 (/ sha1-H3-low 256)) (aset result 15 (% sha1-H3-low 256)) (aset result 16 (/ sha1-H4-high 256)) (aset result 17 (% sha1-H4-high 256)) (aset result 18 (/ sha1-H4-low 256)) (aset result 19 (% sha1-H4-low 256)) result)) ;; do not leave a copy of input string. (fillarray block-high nil) (fillarray block-low nil)))) (defun sha1-string-internal (string &optional binary) (if binary (sha1-binary string) (encode-hex-string (sha1-binary string)))) (defun sha1-region-internal (beg end &optional binary) (sha1-string-internal (buffer-substring-no-properties beg end) binary)) ;;; ;;; application interface. ;;; (defun sha1-region (beg end &optional binary) (if (and sha1-use-external sha1-maximum-internal-length (> (abs (- end beg)) sha1-maximum-internal-length)) (sha1-region-external beg end binary) (sha1-region-internal beg end binary))) (defun sha1-string (string &optional binary) (if (and sha1-use-external sha1-maximum-internal-length (> (length string) sha1-maximum-internal-length)) (sha1-string-external string binary) (sha1-string-internal string binary))) ;;;###autoload (defun sha1 (object &optional beg end binary) "Return the SHA1 (Secure Hash Algorithm) of an object. OBJECT is either a string or a buffer. Optional arguments BEG and END denote buffer positions for computing the hash of a portion of OBJECT. If BINARY is non-nil, return a string in binary form." (if (stringp object) (sha1-string object binary) (with-current-buffer object (sha1-region (or beg (point-min)) (or end (point-max)) binary)))) (provide 'sha1) ;; arch-tag: c0f9abd0-ffc1-4557-aac6-ece7f2d4c901 ;;; sha1.el ends here emacs-jabber-0.8.0/compat/hex-util.el0000644000175100017510000000520211133727374014330 00000000000000;;; hex-util.el --- Functions to encode/decode hexadecimal string. ;; Copyright (C) 1999, 2001, 2002, 2003, 2004, ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ;; Author: Shuhei KOBAYASHI ;; Keywords: data ;; This file is part of FLIM (Faithful Library about Internet Message). ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 3, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Code: (eval-when-compile (defmacro hex-char-to-num (chr) `(let ((chr ,chr)) (cond ((and (<= ?a chr)(<= chr ?f)) (+ (- chr ?a) 10)) ((and (<= ?A chr)(<= chr ?F)) (+ (- chr ?A) 10)) ((and (<= ?0 chr)(<= chr ?9)) (- chr ?0)) (t (error "Invalid hexadecimal digit `%c'" chr))))) (defmacro num-to-hex-char (num) `(aref "0123456789abcdef" ,num))) (defun decode-hex-string (string) "Decode hexadecimal STRING to octet string." (let* ((len (length string)) (dst (make-string (/ len 2) 0)) (idx 0)(pos 0)) (while (< pos len) ;; logior and lsh are not byte-coded. ;; (aset dst idx (logior (lsh (hex-char-to-num (aref string pos)) 4) ;; (hex-char-to-num (aref string (1+ pos))))) (aset dst idx (+ (* (hex-char-to-num (aref string pos)) 16) (hex-char-to-num (aref string (1+ pos))))) (setq idx (1+ idx) pos (+ 2 pos))) dst)) (defun encode-hex-string (string) "Encode octet STRING to hexadecimal string." (let* ((len (length string)) (dst (make-string (* len 2) 0)) (idx 0)(pos 0)) (while (< pos len) ;; logand and lsh are not byte-coded. ;; (aset dst idx (num-to-hex-char (logand (lsh (aref string pos) -4) 15))) (aset dst idx (num-to-hex-char (/ (aref string pos) 16))) (setq idx (1+ idx)) ;; (aset dst idx (num-to-hex-char (logand (aref string pos) 15))) (aset dst idx (num-to-hex-char (% (aref string pos) 16))) (setq idx (1+ idx) pos (1+ pos))) dst)) (provide 'hex-util) ;; arch-tag: fe8aaa79-6c86-400e-813f-5a8cc4cb3859 ;;; hex-util.el ends here emacs-jabber-0.8.0/m4/0000777000175100017510000000000011252722242011360 500000000000000emacs-jabber-0.8.0/m4/emacs-lib.m40000644000175100017510000000170611133727374013407 00000000000000# AX_EMACS_RUN_IFELSE(PROGRAM, ACTION-IF-TRUE, ACTION-IF-FALSE) # ------------------------------------------------------------- # Run PROGRAM in emacs. If it finishes successfully, execute # ACTION-IF-TRUE, else ACTION-IF-FALSE. AC_DEFUN([AX_EMACS_RUN_IFELSE], [cat >conftest.el </dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AM_PROG_INSTALL_SH AM_PROG_INSTALL_STRIP AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) ]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, # 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 10 # AM_PATH_LISPDIR # --------------- AC_DEFUN([AM_PATH_LISPDIR], [AC_PREREQ([2.60])dnl # If set to t, that means we are running in a shell under Emacs. # If you have an Emacs named "t", then use the full path. test x"$EMACS" = xt && EMACS= AC_CHECK_PROGS([EMACS], [emacs xemacs], [no]) AC_ARG_VAR([EMACS], [the Emacs editor command]) AC_ARG_VAR([EMACSLOADPATH], [the Emacs library search path]) AC_ARG_WITH([lispdir], [ --with-lispdir override the default lisp directory], [ lispdir="$withval" AC_MSG_CHECKING([where .elc files should go]) AC_MSG_RESULT([$lispdir])], [ AC_CACHE_CHECK([where .elc files should go], [am_cv_lispdir], [ if test $EMACS != "no"; then if test x${lispdir+set} != xset; then # If $EMACS isn't GNU Emacs or XEmacs, this can blow up pretty badly # Some emacsen will start up in interactive mode, requiring C-x C-c to exit, # which is non-obvious for non-emacs users. # Redirecting /dev/null should help a bit; pity we can't detect "broken" # emacsen earlier and avoid running this altogether. AC_RUN_LOG([$EMACS -batch -q -eval '(while load-path (princ (concat (car load-path) "\n")) (setq load-path (cdr load-path)))' conftest.out]) am_cv_lispdir=`sed -n \ -e 's,/$,,' \ -e '/.*\/lib\/x*emacs\/site-lisp$/{s,.*/lib/\(x*emacs/site-lisp\)$,${libdir}/\1,;p;q;}' \ -e '/.*\/share\/x*emacs\/site-lisp$/{s,.*/share/\(x*emacs/site-lisp\),${datarootdir}/\1,;p;q;}' \ conftest.out` rm conftest.out fi fi test -z "$am_cv_lispdir" && am_cv_lispdir='${datadir}/emacs/site-lisp' ]) lispdir="$am_cv_lispdir" ]) AC_SUBST([lispdir]) ])# AM_PATH_LISPDIR AU_DEFUN([ud_PATH_LISPDIR], [AM_PATH_LISPDIR]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/emacs-lib.m4]) emacs-jabber-0.8.0/fsm.el0000644000175100017510000004001311133727374012072 00000000000000;;; fsm.el --- state machine library ;; Copyright (C) 2006, 2007, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; Version: 0.1ttn4 ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; fsm.el is an exercise in metaprogramming inspired by gen_fsm of ;; Erlang/OTP. It aims to make asynchronous programming in Emacs Lisp ;; easy and fun. By "asynchronous" I mean that long-lasting tasks ;; don't interfer with normal editing. ;; Some people say that it would be nice if Emacs Lisp had threads ;; and/or continuations. They are probably right, but there are few ;; things that can't be made to run in the background using facilities ;; already available: timers, filters and sentinels. As the code can ;; become a bit messy when using such means, with callbacks everywhere ;; and such things, it can be useful to structure the program as a ;; state machine. ;; In this model, a state machine passes between different "states", ;; which are actually only different event handler functions. The ;; state machine receives "events" (from timers, filters, user ;; requests, etc) and reacts to them, possibly entering another state, ;; possibly returning a value. ;; The essential macros/functions are: ;; ;; define-state-machine - create start-FOO function ;; define-state - event handler for each state (required) ;; define-enter-state - called when entering a state (optional) ;; define-fsm - encapsulates the above three (more sugar!) ;; fsm-send - send an event to a state machine ;; fsm-call - send an event and wait for reply ;; fsm.el is similar to but different from Distel: ;; ;; Emacs' tq library is a similar idea. ;; Here is a simple (not using all the features of fsm.el) example: ;; ;; (require 'cl) ;; (labels ((hey (n ev) ;; (message "%d (%s)\tp%sn%s!" n ev ;; (if (zerop (% n 4)) "o" "i") ;; (make-string (max 1 (abs n)) ?g)))) ;; (macrolet ((zow (next timeout) ;; `(progn (hey (incf count) event) ;; (list ,next count ,timeout)))) ;; (define-fsm pingpong ;; :start ((init) "Start a pingpong fsm." ;; (interactive "nInit (number, negative to auto-terminate): ") ;; (list :ping (ash (ash init -2) 2) ; 4 is death ;; (when (interactive-p) 0))) ;; :state-data-name count ;; :states ;; ((:ping ;; (:event (zow :pingg 0.1))) ;; (:pingg ;; (:event (zow :pinggg 0.1))) ;; (:pinggg ;; (:event (zow :pong 1))) ;; (:pong ;; (:event (zow :ping (if (= 0 count) ;; (fsm-goodbye-cruel-world 'pingpong) ;; 3)))))))) ;; ;; (fsm-send (start-pingpong -16) t) ;; ;; Copy into a buffer, uncomment, and type M-x eval-buffer RET. ;; Alternatively, you can replace the `fsm-goodbye-cruel-world' ;; form with `nil', eval just the `labels' form and then type ;; M-x start-pingpong RET -16 RET. ;; NOTE: This is version 0.1ttn4 of fsm.el, with the following ;; mods (an exercise in meta-meta-programming ;-) by ttn: ;; -- Refill for easy (traditional 80-column) perusal. ;; -- New var `fsm-debug-timestamp-format'. ;; -- Make variables satisfy `user-variable-p'. ;; -- Use `format' instead of `concat'. ;; -- New func `fsm-goodbye-cruel-world'. ;; -- Make start-function respect `interactive' spec. ;; -- Make enter-/event-functions anonymous. ;; -- New macro `define-fsm'. ;; -- Example usage in Commentary. ;;; Code: (eval-when-compile (require 'cl)) (defvar fsm-debug "*fsm-debug*" "*Name of buffer for fsm debug messages. If nil, don't output debug messages.") (defvar fsm-debug-timestamp-format nil "*Timestamp format (a string) for `fsm-debug-output'. Default format is whatever `current-time-string' returns followed by a colon and a space.") (defun fsm-debug-output (format &rest args) "Append debug output to buffer named by `fsm-debug'. FORMAT and ARGS are passed to `format'." (when fsm-debug (with-current-buffer (get-buffer-create fsm-debug) (save-excursion (goto-char (point-max)) (insert (if fsm-debug-timestamp-format (format-time-string fsm-debug-timestamp-format) (concat (current-time-string) ": ")) (apply 'format format args) "\n"))))) (defmacro* define-state-machine (name &key start sleep) "Define a state machine class called NAME. A function called start-NAME is created, which uses the argument list and body specified in the :start argument. BODY should return a list of the form (STATE STATE-DATA [TIMEOUT]), where STATE is the initial state (defined by `define-state'), STATE-DATA is any object, and TIMEOUT is the number of seconds before a :timeout event will be sent to the state machine. BODY may refer to the instance being created through the dynamically bound variable `fsm'. SLEEP-FUNCTION, if provided, takes one argument, the number of seconds to sleep while allowing events concerning this state machine to happen. There is probably no reason to change the default, which is accept-process-output with rearranged arguments. \(fn NAME :start ((ARG ...) DOCSTRING BODY) [:sleep SLEEP-FUNCTION])" (declare (debug (&define name :name start &rest &or [":start" (lambda-list [&optional ("interactive" interactive)] stringp def-body)] [":sleep" function-form]))) (let ((start-name (intern (format "start-%s" name))) interactive-spec) (destructuring-bind (arglist docstring &body body) start (when (and (consp (car body)) (eq 'interactive (caar body))) (setq interactive-spec (list (pop body)))) (unless (stringp docstring) (error "Docstring is not a string")) `(progn (put ',name :fsm-enter (make-hash-table :size 11 :test 'eq)) (put ',name :fsm-event (make-hash-table :size 11 :test 'eq)) (defun ,start-name ,arglist ,docstring ,@interactive-spec (fsm-debug-output "Starting %s" ',name) (let ((fsm (list :fsm ',name))) (destructuring-bind (state state-data &optional timeout) (progn ,@body) (nconc fsm (list :state nil :state-data nil :sleep ,(or sleep (lambda (secs) (accept-process-output nil secs))) :deferred nil)) (fsm-update fsm state state-data timeout) fsm))))))) (defmacro* define-state (fsm-name state-name arglist &body body) "Define a state called STATE-NAME in the state machine FSM-NAME. ARGLIST and BODY make a function that gets called when the state machine receives an event in this state. The arguments are: FSM the state machine instance (treat it as opaque) STATE-DATA An object EVENT The occurred event, an object. CALLBACK A function of one argument that expects the response to this event, if any (often `ignore' is used) If the event should return a response, the state machine should arrange to call CALLBACK at some point in the future (not necessarily in this handler). The function should return a list of the form (NEW-STATE NEW-STATE-DATA TIMEOUT): NEW-STATE The next state, a symbol NEW-STATE-DATA An object TIMEOUT A number: send timeout event after this many seconds nil: cancel existing timer :keep: let existing timer continue Alternatively, the function may return the keyword :defer, in which case the event will be resent when the state machine enters another state." (declare (debug (&define name name :name handler lambda-list def-body))) `(setf (gethash ',state-name (get ',fsm-name :fsm-event)) (lambda ,arglist ,@body))) (defmacro* define-enter-state (fsm-name state-name arglist &body body) "Define a function to call when FSM-NAME enters the state STATE-NAME. ARGLIST and BODY make a function that gets called when the state machine enters this state. The arguments are: FSM the state machine instance (treat it as opaque) STATE-DATA An object The function should return a list of the form (NEW-STATE-DATA TIMEOUT): NEW-STATE-DATA An object TIMEOUT A number: send timeout event after this many seconds nil: cancel existing timer :keep: let existing timer continue" (declare (debug (&define name name :name enter lambda-list def-body))) `(setf (gethash ',state-name (get ',fsm-name :fsm-enter)) (lambda ,arglist ,@body))) (defmacro* define-fsm (name &key start sleep states (fsm-name 'fsm) (state-data-name 'state-data) (callback-name 'callback) (event-name 'event)) "Define a state machine class called NAME, along with its STATES. This macro is (further) syntatic sugar for `define-state-machine', `define-state' and `define-enter-state' macros, q.v. NAME is a symbol. Everything else is specified with a keyword arg. START and SLEEP are the same as for `define-state-machine'. STATES is a list, each element having the form (STATE-NAME . STATE-SPEC). STATE-NAME is a symbol. STATE-SPEC is an alist with keys `:event' or `:enter', and values a series of expressions representing the BODY of a `define-state' or `define-enter-state' call, respectively. FSM-NAME, STATE-DATA-NAME, CALLBACK-NAME, and EVENT-NAME are symbols, used to construct the state functions' arglists." `(progn (define-state-machine ,name :start ,start :sleep ,sleep) ,@(loop for (state-name . spec) in states if (assq :enter spec) collect `(define-enter-state ,name ,state-name (,fsm-name ,state-data-name) ,@(cdr it)) end if (assq :event spec) collect `(define-state ,name ,state-name (,fsm-name ,state-data-name ,event-name ,callback-name) ,@(cdr it)) end))) (defun fsm-goodbye-cruel-world (name) "Unbind functions related to fsm NAME (a symbol). Includes start-NAME, and each fsm-NAME-STATE and fsm-NAME-enter-STATE. Functions are `fmakunbound', which will probably give (fatal) pause to any state machines using them. Return nil." (interactive "SUnbind function definitions for fsm named: ") (fmakunbound (intern (format "start-%s" name))) (let (ht) (when (hash-table-p (setq ht (get name :fsm-event))) (clrhash ht) (remprop name :fsm-event)) (when (hash-table-p (setq ht (get name :fsm-enter))) (clrhash ht) (remprop name :fsm-enter))) nil) (defun fsm-start-timer (fsm secs) "Send a timeout event to FSM after SECS seconds. The timer is canceled if another event occurs before, unless the event handler explicitly asks to keep the timer." (fsm-stop-timer fsm) (setf (cddr fsm) (plist-put (cddr fsm) :timeout (run-with-timer secs nil #'fsm-send-sync fsm :timeout)))) (defun fsm-stop-timer (fsm) "Stop the timeout timer of FSM." (let ((timer (plist-get (cddr fsm) :timeout))) (when (timerp timer) (cancel-timer timer) (setf (cddr fsm) (plist-put (cddr fsm) :timeout nil))))) (defun fsm-maybe-change-timer (fsm timeout) "Change the timer of FSM according to TIMEOUT." (cond ((numberp timeout) (fsm-start-timer fsm timeout)) ((null timeout) (fsm-stop-timer fsm)) ;; :keep needs no timer change )) (defun fsm-send (fsm event &optional callback) "Send EVENT to FSM asynchronously. If the state machine generates a response, eventually call CALLBACK with the response as only argument." (run-with-timer 0 nil #'fsm-send-sync fsm event callback)) (defun fsm-update (fsm new-state new-state-data timeout) (let ((fsm-name (cadr fsm)) (old-state (plist-get (cddr fsm) :state))) (plist-put (cddr fsm) :state new-state) (plist-put (cddr fsm) :state-data new-state-data) (fsm-maybe-change-timer fsm timeout) ;; On state change, call enter function and send deferred events ;; again. (unless (eq old-state new-state) (fsm-debug-output "%s enters %s" fsm-name new-state) (let ((enter-fn (gethash new-state (get fsm-name :fsm-enter)))) (when (functionp enter-fn) (fsm-debug-output "Found enter function for %S: %S" new-state enter-fn) (condition-case e (destructuring-bind (newer-state-data newer-timeout) (funcall enter-fn fsm new-state-data) (fsm-debug-output "Using data from enter function") (plist-put (cddr fsm) :state-data newer-state-data) (fsm-maybe-change-timer fsm newer-timeout)) ((debug error) (fsm-debug-output "Didn't work: %S" e))))) (let ((deferred (nreverse (plist-get (cddr fsm) :deferred)))) (setf (cddr fsm) (plist-put (cddr fsm) :deferred nil)) (dolist (event deferred) (apply 'fsm-send-sync fsm event)))))) (defun fsm-send-sync (fsm event &optional callback) "Send EVENT to FSM synchronously. If the state machine generates a response, eventually call CALLBACK with the response as only argument." (save-match-data (let* ((fsm-name (second fsm)) (state (plist-get (cddr fsm) :state)) (state-data (plist-get (cddr fsm) :state-data)) (state-fn (gethash state (get fsm-name :fsm-event)))) ;; If the event is a list, output only the car, to avoid an ;; overflowing debug buffer. (fsm-debug-output "Sent %S to %s in state %s" (or (car-safe event) event) fsm-name state) (let ((result (condition-case e (funcall state-fn fsm state-data event (or callback 'ignore)) ((debug error) (cons :error-signaled e))))) ;; Special case for deferring an event until next state change. (cond ((eq result :defer) (let ((deferred (plist-get (cddr fsm) :deferred))) (plist-put (cddr fsm) :deferred (cons (list event callback) deferred)))) ((null result) (fsm-debug-output "Warning: event %S ignored in state %s/%s" event fsm-name state)) ((eq (car-safe result) :error-signaled) (fsm-debug-output "Error in %s/%s: %s" fsm-name state (error-message-string (cdr result)))) (t (destructuring-bind (new-state new-state-data &optional timeout) result (fsm-update fsm new-state new-state-data timeout)))))))) (defun fsm-call (fsm event) "Send EVENT to FSM synchronously, and wait for a reply. Return the reply. `with-timeout' might be useful." (lexical-let (reply) (fsm-send-sync fsm event (lambda (r) (setq reply (list r)))) (while (null reply) (fsm-sleep fsm 1)) (car reply))) (defun fsm-make-filter (fsm) "Return a filter function that sends events to FSM. Events sent are of the form (:filter PROCESS STRING)." (lexical-let ((fsm fsm)) (lambda (process string) (fsm-send-sync fsm (list :filter process string))))) (defun fsm-make-sentinel (fsm) "Return a sentinel function that sends events to FSM. Events sent are of the form (:sentinel PROCESS STRING)." (lexical-let ((fsm fsm)) (lambda (process string) (fsm-send-sync fsm (list :sentinel process string))))) (defun fsm-sleep (fsm secs) "Sleep up to SECS seconds in a way that lets FSM receive events." (funcall (plist-get (cddr fsm) :sleep) secs)) (defun fsm-get-state-data (fsm) "Return the state data of FSM. Note the absence of a set function. The fsm should manage its state data itself; other code should just send messages to it." (plist-get (cddr fsm) :state-data)) (provide 'fsm) ;;; fsm.el ends here emacs-jabber-0.8.0/jabber-activity.el0000644000175100017510000004016511250455045014365 00000000000000;;; jabber-activity.el --- show jabber activity in the mode line ;; Copyright (C) 2004 Carl Henrik Lunde - ;; This file is a part of jabber.el ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; Allows tracking messages from buddies using the global mode line ;; See (info "(jabber)Tracking activity") ;;; TODO: ;; - Make it possible to enable this mode using M-x customize ;; - When Emacs is on another desktop, (get-buffer-window buf 'visible) ;; returns nil. We need to know when the user selects the frame again ;; so we can remove the string from the mode line. (Or just run ;; jabber-activity-clean often). ;; - jabber-activity-switch-to needs a keybinding. In which map? ;; - Is there any need for having defcustom jabber-activity-make-string? ;; - When there's activity in a buffer it would be nice with a hook which ;; does the opposite of bury-buffer, so switch-to-buffer will show that ;; buffer first. ;;; Code: (require 'jabber-core) (require 'jabber-alert) (require 'jabber-util) (require 'jabber-autoloads) (require 'jabber-muc-nick-completion) ;we need jabber-muc-looks-like-personal-p (require 'cl) (defgroup jabber-activity nil "activity tracking options" :group 'jabber) ;; All the (featurep 'jabber-activity) is so we don't call a function ;; with an autoloaded cookie while the file is loading, since that ;; would lead to endless load recursion. (defcustom jabber-activity-make-string 'jabber-activity-make-string-default "Function to call, for making the string to put in the mode line. The default function returns the nick of the user." :set #'(lambda (var val) (custom-set-default var val) (when (and (featurep 'jabber-activity) (fboundp 'jabber-activity-make-name-alist)) (jabber-activity-make-name-alist) (jabber-activity-mode-line-update))) :type 'function :group 'jabber-activity) (defcustom jabber-activity-shorten-minimum 1 "All strings returned by `jabber-activity-make-strings-shorten' will be at least this long, when possible." :group 'jabber-activity :type 'number) (defcustom jabber-activity-make-strings 'jabber-activity-make-strings-default "Function which should return an alist of JID -> string when given a list of JIDs." :set #'(lambda (var val) (custom-set-default var val) (when (and (featurep 'jabber-activity) (fboundp 'jabber-activity-make-name-alist)) (jabber-activity-make-name-alist) (jabber-activity-mode-line-update))) :type '(choice (function-item :tag "Keep strings" :value jabber-activity-make-strings-default) (function-item :tag "Shorten strings" :value jabber-activity-make-strings-shorten) (function :tag "Other function")) :group 'jabber-activity) (defcustom jabber-activity-count-in-title nil "If non-nil, display number of active JIDs in frame title." :type 'boolean :group 'jabber-activity :set #'(lambda (var val) (custom-set-default var val) (when (and (featurep 'jabber-activity) (bound-and-true-p jabber-activity-mode)) (jabber-activity-mode -1) (jabber-activity-mode 1)))) (defcustom jabber-activity-count-in-title-format '(jabber-activity-jids ("[" jabber-activity-count-string "] ")) "Format string used for displaying activity in frame titles. Same syntax as `mode-line-format'." :type 'sexp :group 'jabber-activity :set #'(lambda (var val) (if (not (and (featurep 'jabber-activity) (bound-and-true-p jabber-activity-mode))) (custom-set-default var val) (jabber-activity-mode -1) (custom-set-default var val) (jabber-activity-mode 1)))) (defcustom jabber-activity-show-p 'jabber-activity-show-p-default "Predicate function to call to check if the given JID should be shown in the mode line or not." :type 'function :group 'jabber-activity) (defcustom jabber-activity-query-unread t "Query the user as to whether killing Emacs should be cancelled when there are unread messages which otherwise would be lost." :type 'boolean :group 'jabber-activity) (defcustom jabber-activity-banned nil "List of regexps of banned JID" :type '(repeat string) :group 'jabber-activity) (defface jabber-activity-face '((t (:foreground "red" :weight bold))) "The face for displaying jabber-activity-string in the mode line" :group 'jabber-activity) (defface jabber-activity-personal-face '((t (:foreground "blue" :weight bold))) "The face for displaying personal jabber-activity-string in the mode line" :group 'jabber-activity) (defvar jabber-activity-jids nil "A list of JIDs which have caused activity") (defvar jabber-activity-name-alist nil "Alist of mode line names for bare JIDs") (defvar jabber-activity-mode-string "" "The mode string for jabber activity") (defvar jabber-activity-count-string "0" "Number of active JIDs as a string.") (defvar jabber-activity-update-hook nil "Hook called when `jabber-activity-jids' changes. It is called after `jabber-activity-mode-string' and `jabber-activity-count-string' are updated.") ;; Protect this variable from being set in Local variables etc. (put 'jabber-activity-mode-string 'risky-local-variable t) (put 'jabber-activity-count-string 'risky-local-variable t) (defun jabber-activity-make-string-default (jid) "Return the nick of the JID. If no nick is available, return the user name part of the JID. In private MUC conversations, return the user's nickname." (if (jabber-muc-sender-p jid) (jabber-jid-resource jid) (let ((nick (jabber-jid-displayname jid)) (user (jabber-jid-user jid)) (username (jabber-jid-username jid))) (if (and username (string= nick user)) username nick)))) (defun jabber-activity-make-strings-default (jids) "Apply `jabber-activity-make-string' on JIDS" (mapcar #'(lambda (jid) (cons jid (funcall jabber-activity-make-string jid))) jids)) (defun jabber-activity-common-prefix (s1 s2) "Return length of common prefix string shared by S1 and S2" (let ((len (min (length s1) (length s2)))) (or (dotimes (i len) (when (not (eq (aref s1 i) (aref s2 i))) (return i))) ;; Substrings, equal, nil, or empty ("") len))) (defun jabber-activity-make-strings-shorten (jids) "Return an alist of JID -> names acquired by running `jabber-activity-make-string' on JIDS, and then shortening the names as much as possible such that all strings still are unique and at least `jabber-activity-shorten-minimum' long." (let ((alist (sort (mapcar #'(lambda (x) (cons x (funcall jabber-activity-make-string x))) jids) #'(lambda (x y) (string-lessp (cdr x) (cdr y)))))) (loop for ((prev-jid . prev) (cur-jid . cur) (next-jid . next)) on (cons nil alist) until (null cur) collect (cons cur-jid (substring cur 0 (min (length cur) (max jabber-activity-shorten-minimum (1+ (jabber-activity-common-prefix cur prev)) (1+ (jabber-activity-common-prefix cur next))))))))) (defun jabber-activity-find-buffer-name (jid) "Find the name of the buffer that messages from JID would use." (or (and (jabber-jid-resource jid) (get-buffer (jabber-muc-private-get-buffer (jabber-jid-user jid) (jabber-jid-resource jid)))) (get-buffer (jabber-chat-get-buffer jid)) (get-buffer (jabber-muc-get-buffer jid)))) (defun jabber-activity-show-p-default (jid) "Returns t only if there is an invisible buffer for JID and JID not in jabber-activity-banned" (let ((buffer (jabber-activity-find-buffer-name jid))) (and (buffer-live-p buffer) (not (get-buffer-window buffer 'visible)) (not (dolist (entry jabber-activity-banned) (when (string-match entry jid) (return t))))))) (defun jabber-activity-make-name-alist () "Rebuild `jabber-activity-name-alist' based on currently known JIDs" (let ((jids (or (mapcar #'car jabber-activity-name-alist) (mapcar #'symbol-name *jabber-roster*)))) (setq jabber-activity-name-alist (funcall jabber-activity-make-strings jids)))) (defun jabber-activity-lookup-name (jid) "Lookup name in `jabber-activity-name-alist', creates an entry if needed, and returns a (jid . string) pair suitable for the mode line" (let ((elm (assoc jid jabber-activity-name-alist))) (if elm elm (progn ;; Remake alist with the new JID (setq jabber-activity-name-alist (funcall jabber-activity-make-strings (cons jid (mapcar #'car jabber-activity-name-alist)))) (jabber-activity-lookup-name jid))))) (defun jabber-activity-mode-line-update (&optional group text presence) "Update the string shown in the mode line using `jabber-activity-make-string' on JIDs where `jabber-activity-show-p'. Optional not-nil GROUP mean that message come from MUC. Optional TEXT used with one-to-one or MUC chats and may be used to identify personal MUC message. Optional PRESENCE mean personal presence request or alert." (setq jabber-activity-mode-string (if jabber-activity-jids (mapconcat (lambda (x) (let ((jump-to-jid (car x))) (jabber-propertize (cdr x) 'face (if (or (and group text (jabber-muc-looks-like-personal-p text group)) ;MUC message (and (not group) text) ;one-to-one chat message presence ;presence request/alert ) 'jabber-activity-personal-face 'jabber-activity-face) ;; XXX: XEmacs doesn't have make-mode-line-mouse-map. ;; Is there another way to make this work? 'local-map (when (fboundp 'make-mode-line-mouse-map) (make-mode-line-mouse-map 'mouse-1 `(lambda () (interactive "@") (jabber-activity-switch-to ,(car x))))) 'help-echo (concat "Jump to " (jabber-jid-displayname (car x)) "'s buffer")))) (mapcar #'jabber-activity-lookup-name jabber-activity-jids) ",") "")) (setq jabber-activity-count-string (number-to-string (length jabber-activity-jids))) (force-mode-line-update 'all) (run-hooks 'jabber-activity-update-hook)) ;;; Hooks (defun jabber-activity-clean () "Remove JIDs where `jabber-activity-show-p' no longer is true" (setq jabber-activity-jids (delete-if-not jabber-activity-show-p jabber-activity-jids)) (jabber-activity-mode-line-update)) (defun jabber-activity-add (from buffer text proposed-alert) "Add a JID to mode line when `jabber-activity-show-p'" (when (funcall jabber-activity-show-p from) (add-to-list 'jabber-activity-jids from) (jabber-activity-mode-line-update nil text))) (defun jabber-activity-add-muc (nick group buffer text proposed-alert) "Add a JID to mode line when `jabber-activity-show-p'" (when (funcall jabber-activity-show-p group) (add-to-list 'jabber-activity-jids group) (jabber-activity-mode-line-update group text))) (defun jabber-activity-presence (who oldstatus newstatus statustext proposed-alert) "Add a JID to mode line on subscription requests." (when (string= newstatus "subscribe") (add-to-list 'jabber-activity-jids (symbol-name who)) (jabber-activity-mode-line-update nil nil t))) (defun jabber-activity-kill-hook () "Query the user as to whether killing Emacs should be cancelled when there are unread messages which otherwise would be lost, if `jabber-activity-query-unread' is t" (if (and jabber-activity-jids jabber-activity-query-unread) (yes-or-no-p "You have unread Jabber messages, are you sure you want to quit?") t)) ;;; Interactive functions (defvar jabber-activity-last-buffer nil "Last non-Jabber buffer used.") (defun jabber-activity-switch-to (&optional jid-param) "If JID-PARAM is provided, switch to that buffer. If JID-PARAM is nil and there has been activity in another buffer, switch to that buffer. If no such buffer exists, switch back to the last non Jabber chat buffer used." (interactive) (if (or jid-param jabber-activity-jids) (let ((jid (or jid-param (car jabber-activity-jids)))) (unless (eq major-mode 'jabber-chat-mode) (setq jabber-activity-last-buffer (current-buffer))) (switch-to-buffer (jabber-activity-find-buffer-name jid)) (jabber-activity-clean)) (if (eq major-mode 'jabber-chat-mode) ;; Switch back to the buffer used last (when (buffer-live-p jabber-activity-last-buffer) (switch-to-buffer jabber-activity-last-buffer)) (message "No new activity")))) (defvar jabber-activity-idle-timer nil "Idle timer used for activity cleaning") ;;;###autoload (define-minor-mode jabber-activity-mode "Toggle display of activity in hidden jabber buffers in the mode line. With a numeric arg, enable this display if arg is positive." :global t :group 'jabber-activity :init-value t (if jabber-activity-mode (progn ;; XEmacs compatibilty hack from erc-track (if (featurep 'xemacs) (defadvice switch-to-buffer (after jabber-activity-update (&rest args) activate) (jabber-activity-clean)) (add-hook 'window-configuration-change-hook 'jabber-activity-clean)) (add-hook 'jabber-message-hooks 'jabber-activity-add) (add-hook 'jabber-muc-hooks 'jabber-activity-add-muc) (add-hook 'jabber-presence-hooks 'jabber-activity-presence) (setq jabber-activity-idle-timer (run-with-idle-timer 2 t 'jabber-activity-clean)) ;; XXX: reactivate ;; (add-hook 'jabber-post-connect-hooks ;; 'jabber-activity-make-name-alist) (add-to-list 'kill-emacs-query-functions 'jabber-activity-kill-hook) (add-to-list 'global-mode-string '(t jabber-activity-mode-string)) (when jabber-activity-count-in-title ;; Be careful not to override specific meanings of the ;; existing title format. In particular, if the car is ;; a symbol, we can't just add our stuff at the beginning. ;; If the car is "", we should be safe. ;; ;; In my experience, sometimes the activity count gets ;; included twice in the title. I'm not sure exactly why, ;; but it would be nice to replace the code below with ;; something cleaner. (if (equal (car frame-title-format) "") (add-to-list 'frame-title-format jabber-activity-count-in-title-format) (setq frame-title-format (list "" jabber-activity-count-in-title-format frame-title-format))) (if (equal (car icon-title-format) "") (add-to-list 'icon-title-format jabber-activity-count-in-title-format) (setq icon-title-format (list "" jabber-activity-count-in-title-format icon-title-format))))) (progn (if (featurep 'xemacs) (ad-disable-advice 'switch-to-buffer 'after 'jabber-activity-update) (remove-hook 'window-configuration-change-hook 'jabber-activity-remove-visible)) (remove-hook 'jabber-message-hooks 'jabber-activity-add) (remove-hook 'jabber-muc-hooks 'jabber-activity-add-muc) (remove-hook 'jabber-presence-hooks 'jabber-activity-presence) (ignore-errors (cancel-timer jabber-activity-idle-timer)) ;; XXX: reactivate ;; (remove-hook 'jabber-post-connect-hooks ;; 'jabber-activity-make-name-alist) (setq global-mode-string (delete '(t jabber-activity-mode-string) global-mode-string)) (setq frame-title-format (delete jabber-activity-count-in-title-format frame-title-format)) (setq icon-title-format (delete jabber-activity-count-in-title-format icon-title-format))))) ;; XXX: define-minor-mode should probably do this for us, but it doesn't. (if jabber-activity-mode (jabber-activity-mode 1)) (provide 'jabber-activity) ;; arch-tag: 127D7E42-356B-11D9-BE1E-000A95C2FCD0 emacs-jabber-0.8.0/jabber-ahc-presence.el0000644000175100017510000001026311133727374015071 00000000000000;; jabber-ahc-presence.el - provide remote control of presence ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-ahc) (require 'jabber-autoloads) (defconst jabber-ahc-presence-node "http://jabber.org/protocol/rc#set-status" "Node used by jabber-ahc-presence") (jabber-ahc-add jabber-ahc-presence-node "Set presence" 'jabber-ahc-presence 'jabber-my-jid-p) (defun jabber-ahc-presence (jc xml-data) "Process presence change command." (let* ((query (jabber-iq-query xml-data)) (sessionid (jabber-xml-get-attribute query 'sessionid)) (action (jabber-xml-get-attribute query 'action))) ;; No session state is kept; instead, lack of session-id is used ;; as indication of first command. (cond ;; command cancelled ((string= action "cancel") `(command ((xmlns . "http://jabber.org/protocol/commands") (sessionid . ,sessionid) (node . ,jabber-ahc-presence-node) (status . "canceled")))) ;; return form ((null sessionid) `(command ((xmlns . "http://jabber.org/protocol/commands") (sessionid . "jabber-ahc-presence") (node . ,jabber-ahc-presence-node) (status . "executing")) (x ((xmlns . "jabber:x:data") (type . "form")) (title nil ,(format "Set presence of %s" (jabber-connection-jid jc))) (instructions nil "Select new presence status.") (field ((var . "FORM_TYPE") (type . "hidden")) (value nil "http://jabber.org/protocol/rc")) (field ((var . "status") (label . "Status") (type . "list-single")) (value nil ,(if (string= *jabber-current-show* "") "online" *jabber-current-show*)) (option ((label . "Online")) (value nil "online")) (option ((label . "Chatty")) (value nil "chat")) (option ((label . "Away")) (value nil "away")) (option ((label . "Extended away")) (value nil "xa")) (option ((label . "Do not disturb")) (value nil "dnd"))) (field ((var . "status-message") (label . "Message") (type . "text-single")) (value nil ,*jabber-current-status*)) (field ((var . "status-priority") (label . "Priority") (type . "text-single")) (value nil ,(int-to-string *jabber-current-priority*)))))) ;; process form (t (let* ((x (car (jabber-xml-get-children query 'x))) ;; we assume that the first is the jabber:x:data one (fields (jabber-xml-get-children x 'field)) (new-show *jabber-current-show*) (new-status *jabber-current-status*) (new-priority *jabber-current-priority*)) (dolist (field fields) (let ((var (jabber-xml-get-attribute field 'var)) ;; notice that multi-value fields won't be handled properly ;; by this (value (car (jabber-xml-node-children (car (jabber-xml-get-children field 'value)))))) (cond ((string= var "status") (setq new-show (if (string= value "online") "" value))) ((string= var "status-message") (setq new-status value)) ((string= var "status-priority") (setq new-priority (string-to-number value)))))) (jabber-send-presence new-show new-status new-priority)) `(command ((xmlns . "http://jabber.org/protocol/commands") (sessionid . ,sessionid) (node . ,jabber-ahc-presence-node) (status . "completed")) (note ((type . "info")) "Presence has been changed.")))))) (provide 'jabber-ahc-presence) ;;; arch-tag: 4b8cbbe7-00a9-4d42-a4ac-b824ab914fba emacs-jabber-0.8.0/jabber-ahc.el0000644000175100017510000002052511133727374013271 00000000000000;; jabber-ahc.el - Ad-Hoc Commands by JEP-0050 ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-disco) (require 'jabber-widget) (require 'jabber-autoloads) (defvar jabber-ahc-sessionid nil "session id of Ad-Hoc Command session") (defvar jabber-ahc-node nil "node to send commands to") (defvar jabber-ahc-commands nil "Commands provided This is an alist, where the keys are node names as strings (which means that they must not conflict). The values are plists having following properties: acl - function taking connection object and JID of requester, returning non-nil for access allowed. No function means open for everyone. name - name of command func - function taking connection object and entire IQ stanza as arguments and returning a node Use the function `jabber-ahc-add' to add a command to this list.") ;;; SERVER (add-to-list 'jabber-disco-info-nodes (list "http://jabber.org/protocol/commands" '((identity ((category . "automation") (type . "command-list") (name . "Ad-Hoc Command list"))) (feature ((var . "http://jabber.org/protocol/commands"))) (feature ((var . "http://jabber.org/protocol/disco#items"))) (feature ((var . "http://jabber.org/protocol/disco#info")))))) (defun jabber-ahc-add (node name func acl) "Add a command to internal lists. NODE is the node name to be used. It must be unique. NAME is the natural-language name of the command. FUNC is a function taking the entire IQ stanza as single argument when this command is invoked, and returns a node. ACL is a function taking JID as single argument, returning non-nil for access allowed. nil means open for everyone." (add-to-list 'jabber-ahc-commands (cons node (list 'name name 'func func 'acl acl))) (add-to-list 'jabber-disco-info-nodes (list node `((identity ((category . "automation") (type . "command-node") (name . ,name))) (feature ((var . "http://jabber.org/protocol/commands"))) (feature ((var . "http://jabber.org/protocol/disco#info"))) (feature ((var . "jabber:x:data"))))))) (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/commands") (add-to-list 'jabber-disco-items-nodes (list "http://jabber.org/protocol/commands" #'jabber-ahc-disco-items nil)) (defun jabber-ahc-disco-items (jc xml-data) "Return commands in response to disco#items request" (let ((jid (jabber-xml-get-attribute xml-data 'from))) (mapcar (function (lambda (command) (let ((node (car command)) (plist (cdr command))) (let ((acl (plist-get plist 'acl)) (name (plist-get plist 'name)) (func (plist-get plist 'func))) (when (or (not (functionp acl)) (funcall acl jc jid)) `(item ((name . ,name) (jid . ,(jabber-connection-jid jc)) (node . ,node)))))))) jabber-ahc-commands))) (add-to-list 'jabber-iq-set-xmlns-alist (cons "http://jabber.org/protocol/commands" 'jabber-ahc-process)) (defun jabber-ahc-process (jc xml-data) (let ((to (jabber-xml-get-attribute xml-data 'from)) (id (jabber-xml-get-attribute xml-data 'id)) (node (jabber-xml-get-attribute (jabber-iq-query xml-data) 'node))) ;; find command (let* ((plist (cdr (assoc node jabber-ahc-commands))) (acl (plist-get plist 'acl)) (func (plist-get plist 'func))) (if plist ;; found (if (or (not (functionp acl)) (funcall acl jc to)) ;; access control passed (jabber-send-iq jc to "result" (funcall func jc xml-data) nil nil nil nil id) ;; ...or failed (jabber-signal-error "cancel" 'not-allowed)) ;; No such node (jabber-signal-error "cancel" 'item-not-found))))) ;;; CLIENT (add-to-list 'jabber-jid-service-menu (cons "Request command list" 'jabber-ahc-get-list)) (defun jabber-ahc-get-list (jc to) "Request list of ad-hoc commands. (JEP-0050)" (interactive (list (jabber-read-account) (jabber-read-jid-completing "Request command list from: "))) (jabber-get-disco-items jc to "http://jabber.org/protocol/commands")) (add-to-list 'jabber-jid-service-menu (cons "Execute command" 'jabber-ahc-execute-command)) (defun jabber-ahc-execute-command (jc to node) "Execute ad-hoc command. (JEP-0050)" (interactive (list (jabber-read-account) (jabber-read-jid-completing "Execute command of: ") (jabber-read-node "Node of command: "))) (jabber-send-iq jc to "set" `(command ((xmlns . "http://jabber.org/protocol/commands") (node . ,node) (action . "execute"))) #'jabber-process-data #'jabber-ahc-display #'jabber-process-data "Command execution failed")) (defun jabber-ahc-display (jc xml-data) (let* ((from (jabber-xml-get-attribute xml-data 'from)) (query (jabber-iq-query xml-data)) (node (jabber-xml-get-attribute query 'node)) (notes (jabber-xml-get-children query 'note)) (sessionid (jabber-xml-get-attribute query 'sessionid)) (status (jabber-xml-get-attribute query 'status)) (actions (car (jabber-xml-get-children query 'actions))) xdata (inhibit-read-only t)) (make-local-variable 'jabber-ahc-sessionid) (setq jabber-ahc-sessionid sessionid) (make-local-variable 'jabber-ahc-node) (setq jabber-ahc-node node) (make-local-variable 'jabber-buffer-connection) (setq jabber-buffer-connection jc) (dolist (x (jabber-xml-get-children query 'x)) (when (string= (jabber-xml-get-attribute x 'xmlns) "jabber:x:data") (setq xdata x))) (cond ((string= status "executing") (insert "Executing command\n\n")) ((string= status "completed") (insert "Command completed\n\n")) ((string= status "canceled") (insert "Command canceled\n\n"))) (dolist (note notes) (let ((note-type (jabber-xml-get-attribute note 'type))) (cond ((string= note-type "warn") (insert "Warning: ")) ((string= note-type "error") (insert "Error: "))) (insert (car (jabber-xml-node-children note)) "\n"))) (insert "\n") (when xdata (jabber-init-widget-buffer from) (let ((formtype (jabber-xml-get-attribute xdata 'type))) (if (string= formtype "result") (jabber-render-xdata-search-results xdata) (jabber-render-xdata-form xdata) (when (string= status "executing") (let ((button-titles (cond ((null actions) '(complete cancel)) (t (let ((children (mapcar #'jabber-xml-node-name (jabber-xml-node-children actions))) (default-action (jabber-xml-get-attribute actions 'execute))) (if (or (null default-action) (memq (intern default-action) children)) children (cons (intern default-action) children))))))) (dolist (button-title button-titles) (widget-create 'push-button :notify `(lambda (&rest ignore) (jabber-ahc-submit (quote ,button-title))) (symbol-name button-title)) (widget-insert "\t"))) (widget-insert "\n")))) (widget-setup) (widget-minor-mode 1)))) (defun jabber-ahc-submit (action) "Submit Ad-Hoc Command." (jabber-send-iq jabber-buffer-connection jabber-submit-to "set" `(command ((xmlns . "http://jabber.org/protocol/commands") (sessionid . ,jabber-ahc-sessionid) (node . ,jabber-ahc-node) (action . ,(symbol-name action))) ,(if (and (not (eq action 'cancel)) (eq jabber-form-type 'xdata)) (jabber-parse-xdata-form))) #'jabber-process-data #'jabber-ahc-display #'jabber-process-data "Command execution failed")) (provide 'jabber-ahc) ;;; arch-tag: c0d5ed8c-50cb-44e1-8e0f-4058b79ee353 emacs-jabber-0.8.0/jabber-alert.el0000644000175100017510000004705511250455045013645 00000000000000;; jabber-alert.el - alert hooks ;; Copyright (C) 2003, 2004, 2005, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-util) (require 'jabber-autoloads) (require 'cl) (defgroup jabber-alerts nil "auditory and visual alerts for jabber events" :group 'jabber) (defcustom jabber-alert-message-hooks '(jabber-message-echo jabber-message-scroll) "Hooks run when a new message arrives. Arguments are FROM, BUFFER, TEXT and PROPOSED-ALERT. FROM is the JID of the sender, BUFFER is the the buffer where the message can be read, and TEXT is the text of the message. PROPOSED-ALERT is the string returned by `jabber-alert-message-function' for these arguments, so that hooks do not have to call it themselves. This hook is meant for user customization of message alerts. For other uses, see `jabber-message-hooks'." :type 'hook :options '(jabber-message-beep jabber-message-wave jabber-message-echo jabber-message-switch jabber-message-display jabber-message-scroll) :group 'jabber-alerts) (defvar jabber-message-hooks nil "Internal hooks run when a new message arrives. This hook works just like `jabber-alert-message-hooks', except that it's not meant to be customized by the user.") (defcustom jabber-alert-message-function 'jabber-message-default-message "Function for constructing message alert messages. Arguments are FROM, BUFFER, and TEXT. This function should return a string containing an appropriate text message, or nil if no message should be displayed. The provided hooks displaying a text message get it from this function, and show no message if it returns nil. Other hooks do what they do every time." :type 'function :group 'jabber-alerts) (defcustom jabber-alert-muc-hooks '(jabber-muc-echo jabber-muc-scroll) "Hooks run when a new MUC message arrives. Arguments are NICK, GROUP, BUFFER, TEXT and PROPOSED-ALERT. NICK is the nickname of the sender. GROUP is the JID of the group. BUFFER is the the buffer where the message can be read, and TEXT is the text of the message. PROPOSED-ALERT is the string returned by `jabber-alert-muc-function' for these arguments, so that hooks do not have to call it themselves." :type 'hook :options '(jabber-muc-beep jabber-muc-wave jabber-muc-echo jabber-muc-switch jabber-muc-display jabber-muc-scroll) :group 'jabber-alerts) (defvar jabber-muc-hooks '() "Internal hooks run when a new MUC message arrives. This hook works just like `jabber-alert-muc-hooks', except that it's not meant to be customized by the user.") (defcustom jabber-alert-muc-function 'jabber-muc-default-message "Function for constructing message alert messages. Arguments are NICK, GROUP, BUFFER, and TEXT. This function should return a string containing an appropriate text message, or nil if no message should be displayed. The provided hooks displaying a text message get it from this function, and show no message if it returns nil. Other hooks do what they do every time." :type 'function :group 'jabber-alerts) (defcustom jabber-alert-presence-hooks '(jabber-presence-echo) "Hooks run when a user's presence changes. Arguments are WHO, OLDSTATUS, NEWSTATUS, STATUSTEXT and PROPOSED-ALERT. WHO is a symbol whose text is the JID of the contact, and which has various interesting properties. OLDSTATUS is the old presence or nil if disconnected. NEWSTATUS is the new presence, or one of \"subscribe\", \"unsubscribe\", \"subscribed\" and \"unsubscribed\". PROPOSED-ALERT is the string returned by `jabber-alert-presence-message-function' for these arguments." :type 'hook :options '(jabber-presence-beep jabber-presence-wave jabber-presence-switch jabber-presence-display jabber-presence-echo) :group 'jabber-alerts) (defvar jabber-presence-hooks '(jabber-presence-watch) "Internal hooks run when a user's presence changes. This hook works just like `jabber-alert-presence-hooks', except that it's not meant to be customized by the user.") (defcustom jabber-alert-presence-message-function 'jabber-presence-default-message "Function for constructing presence alert messages. Arguments are WHO, OLDSTATUS, NEWSTATUS and STATUSTEXT. See `jabber-alert-presence-hooks' for documentation. This function should return a string containing an appropriate text message, or nil if no message should be displayed. The provided hooks displaying a text message get it from this function. All hooks refrain from action if this function returns nil." :type 'function :group 'jabber-alerts) (defcustom jabber-alert-info-message-hooks '(jabber-info-display jabber-info-echo) "Hooks run when an info request is completed. First argument is WHAT, a symbol telling the kind of info request completed. That might be 'roster, for requested roster updates, and 'browse, for browse requests. Second argument in BUFFER, a buffer containing the result. Third argument is PROPOSED-ALERT, containing the string returned by `jabber-alert-info-message-function' for these arguments." :type 'hook :options '(jabber-info-beep jabber-info-wave jabber-info-echo jabber-info-switch jabber-info-display) :group 'jabber-alerts) (defvar jabber-info-message-hooks '() "Internal hooks run when an info request is completed. This hook works just like `jabber-alert-info-message-hooks', except that it's not meant to be customized by the user.") (defcustom jabber-alert-info-message-function 'jabber-info-default-message "Function for constructing info alert messages. Arguments are WHAT, a symbol telling the kind of info request completed, and BUFFER, a buffer containing the result." :type 'function :group 'jabber-alerts) (defcustom jabber-info-message-alist '((roster . "Roster display updated") (browse . "Browse request completed")) "Alist for info alert messages, used by `jabber-info-default-message'." :type '(alist :key-type symbol :value-type string :options (roster browse)) :group 'jabber-alerts) (defcustom jabber-alert-message-wave "" "A sound file to play when a message arrived. See `jabber-alert-message-wave-alist' if you want other sounds for specific contacts." :type 'file :group 'jabber-alerts) (defcustom jabber-alert-message-wave-alist nil "Specific sound files for messages from specific contacts. The keys are regexps matching the JID, and the values are sound files." :type '(alist :key-type regexp :value-type file) :group 'jabber-alerts) (defcustom jabber-alert-muc-wave "" "a sound file to play when a MUC message arrived" :type 'file :group 'jabber-alerts) (defcustom jabber-alert-presence-wave "" "a sound file to play when a presence arrived" :type 'file :group 'jabber-alerts) (defcustom jabber-alert-presence-wave-alist nil "Specific sound files for presence from specific contacts. The keys are regexps matching the JID, and the values are sound files." :type '(alist :key-type regexp :value-type file) :group 'jabber-alerts) (defcustom jabber-alert-info-wave "" "a sound file to play when an info query result arrived" :type 'file :group 'jabber-alerts) (defcustom jabber-play-sound-file 'play-sound-file "a function to call to play alert sound files" :type 'function :group 'jabber-alerts) (defmacro define-jabber-alert (name docstring function) "Define a new family of external alert hooks. Use this macro when your hooks do nothing except displaying a string in some new innovative way. You write a string display function, and this macro does all the boring and repetitive work. NAME is the name of the alert family. The resulting hooks will be called jabber-{message,muc,presence,info}-NAME. DOCSTRING is the docstring to use for those hooks. FUNCTION is a function that takes one argument, a string, and displays it in some meaningful way. It can be either a lambda form or a quoted function name. The created functions are inserted as options in Customize. Examples: \(define-jabber-alert foo \"Send foo alert\" 'foo-message) \(define-jabber-alert bar \"Send bar alert\" (lambda (msg) (bar msg 42)))" (let ((sn (symbol-name name))) (let ((msg (intern (format "jabber-message-%s" sn))) (muc (intern (format "jabber-muc-%s" sn))) (pres (intern (format "jabber-presence-%s" sn))) (info (intern (format "jabber-info-%s" sn)))) `(progn (defun ,msg (from buffer text proposed-alert) ,docstring (when proposed-alert (funcall ,function proposed-alert))) (pushnew (quote ,msg) (get 'jabber-alert-message-hooks 'custom-options)) (defun ,muc (nick group buffer text proposed-alert) ,docstring (when proposed-alert (funcall ,function proposed-alert))) (pushnew (quote ,muc) (get 'jabber-alert-muc-hooks 'custom-options)) (defun ,pres (who oldstatus newstatus statustext proposed-alert) ,docstring (when proposed-alert (funcall ,function proposed-alert))) (pushnew (quote ,pres) (get 'jabber-alert-presence-hooks 'custom-options)) (defun ,info (infotype buffer proposed-alert) ,docstring (when proposed-alert (funcall ,function proposed-alert))) (pushnew (quote ,info) (get 'jabber-alert-info-message-hooks 'custom-options)))))) ;; Alert hooks (define-jabber-alert echo "Show a message in the echo area" (lambda (msg) (message "%s" msg))) (define-jabber-alert beep "Beep on event" (lambda (&rest ignore) (beep))) ;; Message alert hooks (defun jabber-message-default-message (from buffer text) (when (or jabber-message-alert-same-buffer (not (memq (selected-window) (get-buffer-window-list buffer)))) (if (jabber-muc-sender-p from) (format "Private message from %s in %s" (jabber-jid-resource from) (jabber-jid-displayname (jabber-jid-user from))) (format "Message from %s" (jabber-jid-displayname from))))) (defcustom jabber-message-alert-same-buffer t "If nil, don't display message alerts for the current buffer." :type 'boolean :group 'jabber-alerts) (defcustom jabber-muc-alert-self nil "If nil, don't display MUC alerts for your own messages." :type 'boolean :group 'jabber-alerts) (defun jabber-message-wave (from buffer text proposed-alert) "Play the wave file specified in `jabber-alert-message-wave'" (when proposed-alert (let* ((case-fold-search t) (bare-jid (jabber-jid-user from)) (sound-file (or (dolist (entry jabber-alert-message-wave-alist) (when (string-match (car entry) bare-jid) (return (cdr entry)))) jabber-alert-message-wave))) (unless (equal sound-file "") (funcall jabber-play-sound-file sound-file))))) (defun jabber-message-display (from buffer text proposed-alert) "Display the buffer where a new message has arrived." (when proposed-alert (display-buffer buffer))) (defun jabber-message-switch (from buffer text proposed-alert) "Switch to the buffer where a new message has arrived." (when proposed-alert (switch-to-buffer buffer))) (defun jabber-message-scroll (from buffer text proposed-alert) "Scroll all nonselected windows where the chat buffer is displayed." ;; jabber-chat-buffer-display will DTRT with point in the buffer. ;; But this change will not take effect in nonselected windows. ;; Therefore we do that manually here. ;; ;; There are three cases: ;; 1. The user started typing a message in this window. Point is ;; greater than jabber-point-insert. In that case, we don't ;; want to move point. ;; 2. Point was at the end of the buffer, but no message was being ;; typed. After displaying the message, point is now close to ;; the end of the buffer. We advance it to the end. ;; 3. The user was perusing history in this window. There is no ;; simple way to distinguish this from 2, so the user loses. (let ((windows (get-buffer-window-list buffer nil t)) (new-point-max (with-current-buffer buffer (point-max)))) (dolist (w windows) (unless (eq w (selected-window)) (set-window-point w new-point-max))))) ;; MUC alert hooks (defun jabber-muc-default-message (nick group buffer text) (when (or jabber-message-alert-same-buffer (not (memq (selected-window) (get-buffer-window-list buffer)))) (if nick (when (or jabber-muc-alert-self (not (string= nick (cdr (assoc group *jabber-active-groupchats*))))) (format "Message from %s in %s" nick (jabber-jid-displayname group))) (format "Message in %s" (jabber-jid-displayname group))))) (defun jabber-muc-wave (nick group buffer text proposed-alert) "Play the wave file specified in `jabber-alert-muc-wave'" (when proposed-alert (funcall jabber-play-sound-file jabber-alert-muc-wave))) (defun jabber-muc-display (nick group buffer text proposed-alert) "Display the buffer where a new message has arrived." (when proposed-alert (display-buffer buffer))) (defun jabber-muc-switch (nick group buffer text proposed-alert) "Switch to the buffer where a new message has arrived." (when proposed-alert (switch-to-buffer buffer))) (defun jabber-muc-scroll (nick group buffer text proposed-alert) "Scroll buffer even if it is in an unselected window." (jabber-message-scroll nil buffer nil nil)) ;; Presence alert hooks (defun jabber-presence-default-message (who oldstatus newstatus statustext) "This function returns nil if OLDSTATUS and NEWSTATUS are equal, and in other cases a string of the form \"'name' (jid) is now NEWSTATUS (STATUSTEXT)\". This function is not called directly, but is the default for `jabber-alert-presence-message-function'." (cond ((equal oldstatus newstatus) nil) (t (let ((formattedname (if (> (length (get who 'name)) 0) (get who 'name) (symbol-name who))) (formattedstatus (or (cdr (assoc newstatus '(("subscribe" . " requests subscription to your presence") ("subscribed" . " has granted presence subscription to you") ("unsubscribe" . " no longer subscribes to your presence") ("unsubscribed" . " cancels your presence subscription")))) (concat " is now " (or (cdr (assoc newstatus jabber-presence-strings)) newstatus)))) (formattedtext (if (> (length statustext) 0) (concat " (" statustext ")") ""))) (concat formattedname formattedstatus formattedtext))))) (defun jabber-presence-only-chat-open-message (who oldstatus newstatus statustext) "This function returns the same as `jabber-presence-default-message' but only if there is a chat buffer open for WHO, keeping the amount of presence messages at a more manageable level when there are lots of users. This function is not called directly, but can be used as the value for `jabber-alert-presence-message-function'." (when (get-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from))) (jabber-presence-default-message who oldstatus newstatus statustext))) (defun jabber-presence-wave (who oldstatus newstatus statustext proposed-alert) "Play the wave file specified in `jabber-alert-presence-wave'" (when proposed-alert (let* ((case-fold-search t) (bare-jid (symbol-name who)) (sound-file (or (dolist (entry jabber-alert-presence-wave-alist) (when (string-match (car entry) bare-jid) (return (cdr entry)))) jabber-alert-presence-wave))) (unless (equal sound-file "") (funcall jabber-play-sound-file sound-file))))) ;; This is now defined in jabber-roster.el. ;; (defun jabber-presence-update-roster (who oldstatus newstatus statustext proposed-alert) ;; "Update the roster display by calling `jabber-display-roster'" ;; (jabber-display-roster)) (defun jabber-presence-display (who oldstatus newstatus statustext proposed-alert) "Display the roster buffer" (when proposed-alert (display-buffer jabber-roster-buffer))) (defun jabber-presence-switch (who oldstatus newstatus statustext proposed-alert) "Switch to the roster buffer" (when proposed-alert (switch-to-buffer jabber-roster-buffer))) ;;; Info alert hooks (defun jabber-info-default-message (infotype buffer) "Function for constructing info alert messages. The argument is INFOTYPE, a symbol telling the kind of info request completed. This function uses `jabber-info-message-alist' to find a message." (concat (cdr (assq infotype jabber-info-message-alist)) " (buffer "(buffer-name buffer) ")")) (defun jabber-info-wave (infotype buffer proposed-alert) "Play the wave file specified in `jabber-alert-info-wave'" (if proposed-alert (funcall jabber-play-sound-file jabber-alert-info-wave))) (defun jabber-info-display (infotype buffer proposed-alert) "Display buffer of completed request" (when proposed-alert (display-buffer buffer))) (defun jabber-info-switch (infotype buffer proposed-alert) "Switch to buffer of completed request" (when proposed-alert (switch-to-buffer buffer))) ;;; Personal alert hooks (defmacro define-personal-jabber-alert (name) "From ALERT function, make ALERT-personal function. Makes sence only for MUC." (let ((sn (symbol-name name))) (let ((func (intern (format "%s-personal" sn)))) `(progn (defun ,func (nick group buffer text proposed-alert) (if (jabber-muc-looks-like-personal-p text group) (,name nick group buffer text proposed-alert))) (pushnew (quote ,func) (get 'jabber-alert-muc-hooks 'custom-options))))) ) (define-personal-jabber-alert jabber-muc-beep) (define-personal-jabber-alert jabber-muc-wave) (define-personal-jabber-alert jabber-muc-echo) (define-personal-jabber-alert jabber-muc-switch) (define-personal-jabber-alert jabber-muc-display) (defcustom jabber-autoanswer-alist nil "Specific phrases to autoanswer on specific message. The keys are regexps matching the incoming message text, and the values are autoanswer phrase." :type '(alist :key-type regexp :value-type string) :group 'jabber-alerts) (defun jabber-autoanswer-answer (from buffer text proposed-alert) "Answer automaticaly when incoming text matches first element of `jabber-autoanswer-alist'" (when (and from buffer text proposed-alert jabber-autoanswer-alist) (let ((message (dolist (entry jabber-autoanswer-alist) (when (string-match (car entry) text) (return (cdr entry)))))) (if message (jabber-chat-send jabber-buffer-connection message))) )) (pushnew 'jabber-autoanswer-answer (get 'jabber-alert-message-hooks 'custom-options)) (defun jabber-autoanswer-answer-muc (nick group buffer text proposed-alert) "Answer automaticaly when incoming text matches first element of `jabber-autoanswer-alist'" (when (and nick group buffer text proposed-alert jabber-autoanswer-alist) (let ((message (dolist (entry jabber-autoanswer-alist) (when (string-match (car entry) text) (return (cdr entry)))))) (if message (jabber-chat-send jabber-buffer-connection message))) )) (pushnew 'jabber-autoanswer-answer-muc (get 'jabber-alert-muc-hooks 'custom-options)) (provide 'jabber-alert) ;;; arch-tag: 725bd73e-c613-4fdc-a11d-3392a7598d4f emacs-jabber-0.8.0/jabber-autoaway.el0000644000175100017510000001465211133727374014374 00000000000000;;; jabber-autoaway.el --- change status to away after idleness ;; Copyright (C) 2006, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. (eval-when-compile (require 'cl)) (require 'time-date) (defgroup jabber-autoaway nil "Change status to away after idleness" :group 'jabber) (defcustom jabber-autoaway-method (cond ((fboundp 'current-idle-time) 'jabber-current-idle-time) ((getenv "DISPLAY") 'jabber-xprintidle-get-idle-time) ((null window-system) 'jabber-termatime-get-idle-time)) "Method used to keep track of idleness. This is a function that takes no arguments, and returns the number of seconds since the user was active, or nil on error." :group 'jabber-autoaway :type '(choice (const :tag "Use `current-idle-time' function" jabber-current-idle-time) (const :tag "xprintidle" jabber-xprintidle-get-idle-time) (const :tag "Watch atime of terminal" jabber-termatime-get-idle-time) function (const :tag "None" nil))) (defcustom jabber-autoaway-timeout 5 "Minutes of inactivity before changing status to away" :group 'jabber-autoaway :type 'number) (defcustom jabber-autoaway-status "Idle" "Status string for autoaway" :group 'jabber-autoaway :type 'string) (defcustom jabber-autoaway-priority nil "Priority for autoaway. If nil, don't change priority. See the manual for more information about priority." :group 'jabber-autoaway :type '(choice (const :tag "Don't change") (integer :tag "Priority")) :link '(info-link "(jabber)Presence")) (defcustom jabber-xprintidle-program (executable-find "xprintidle") "Name of the xprintidle program" :group 'jabber-autoaway :type 'string) (defcustom jabber-autoaway-verbose nil "If nil, don't print autoaway status messages." :group 'jabber-autoaway :type 'boolean) (defvar jabber-autoaway-timer nil) (defvar jabber-autoaway-last-idle-time nil "Seconds of idle time the last time we checked. This is used to detect whether the user has become unidle.") (defun jabber-autoaway-message (&rest args) (when jabber-autoaway-verbose (apply #'message args))) ;;;###autoload (defun jabber-autoaway-start (&optional ignored) "Start autoaway timer. The IGNORED argument is there so you can put this function in `jabber-post-connect-hooks'." (interactive) (unless jabber-autoaway-timer (setq jabber-autoaway-timer (run-with-timer (* jabber-autoaway-timeout 60) nil #'jabber-autoaway-timer)) (jabber-autoaway-message "Autoaway timer started"))) (defun jabber-autoaway-stop () "Stop autoaway timer." (interactive) (when jabber-autoaway-timer (jabber-cancel-timer jabber-autoaway-timer) (setq jabber-autoaway-timer nil) (jabber-autoaway-message "Autoaway timer stopped"))) (defun jabber-autoaway-get-idle-time () "Get idle time in seconds according to chosen method. Return nil on error." (when jabber-autoaway-method (funcall jabber-autoaway-method))) (defun jabber-autoaway-timer () ;; We use one-time timers, so reset the variable. (setq jabber-autoaway-timer nil) (let ((idle-time (jabber-autoaway-get-idle-time))) (when (numberp idle-time) ;; Has "idle timeout" passed? (if (> idle-time (* 60 jabber-autoaway-timeout)) ;; If so, mark ourselves idle. (jabber-autoaway-set-idle) ;; Else, start a timer for the remaining amount. (setq jabber-autoaway-timer (run-with-timer (- (* 60 jabber-autoaway-timeout) idle-time) nil #'jabber-autoaway-timer)))))) (defun jabber-autoaway-set-idle () (jabber-autoaway-message "Autoaway triggered") ;; Send presence, unless the user has set a custom presence (unless (member *jabber-current-show* '("away" "xa" "dnd")) (jabber-send-presence "away" jabber-autoaway-status (or jabber-autoaway-priority *jabber-current-priority*))) (setq jabber-autoaway-last-idle-time (jabber-autoaway-get-idle-time)) ;; Run unidle timer every 10 seconds (setq jabber-autoaway-timer (run-with-timer 10 10 #'jabber-autoaway-maybe-unidle))) (defun jabber-autoaway-maybe-unidle () (let ((idle-time (jabber-autoaway-get-idle-time))) (jabber-autoaway-message "Idle for %d seconds" idle-time) ;; As long as idle time increases monotonically, stay idle. (if (> idle-time jabber-autoaway-last-idle-time) (progn (setq jabber-autoaway-last-idle-time idle-time)) ;; But if it doesn't, go back to unidle state. (jabber-autoaway-message "Back to unidle") ;; But don't mess with the user's custom presence. (if (string= *jabber-current-status* jabber-autoaway-status) (jabber-send-default-presence) (jabber-autoaway-message "%S /= %S - not resetting presence" *jabber-current-status* jabber-autoaway-status)) (jabber-autoaway-stop) (jabber-autoaway-start)))) (defun jabber-xprintidle-get-idle-time () "Get idle time through the xprintidle program." (when jabber-xprintidle-program (with-temp-buffer (when (zerop (call-process jabber-xprintidle-program nil t)) (/ (string-to-number (buffer-string)) 1000.0))))) (defun jabber-termatime-get-idle-time () "Get idle time through atime of terminal. The method for finding the terminal only works on GNU/Linux." (let ((terminal (cond ((file-exists-p "/proc/self/fd/0") "/proc/self/fd/0") (t nil)))) (when terminal (let* ((atime-of-tty (nth 4 (file-attributes terminal))) (diff (time-to-seconds (time-since atime-of-tty)))) (when (> diff 0) diff))))) (defun jabber-current-idle-time () "Get idle time through `current-idle-time'. `current-idle-time' was introduced in Emacs 22." (let ((idle-time (current-idle-time))) (if (null idle-time) 0 (float-time idle-time)))) (provide 'jabber-autoaway) ;; arch-tag: 5bcea14c-842d-11da-a120-000a95c2fcd0 emacs-jabber-0.8.0/jabber-avatar.el0000644000175100017510000001665511133727374014025 00000000000000;;; jabber-avatar.el --- generic functions for avatars ;; Copyright (C) 2006, 2007, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; There are several methods for transporting avatars in Jabber ;; (JEP-0008, JEP-0084, JEP-0153). They all have in common that they ;; identify avatars by their SHA1 checksum, and (at least partially) ;; use Base64-encoded image data. Thus this library of support ;; functions for interpreting and caching avatars. ;; A contact with an avatar has the image in the avatar property of ;; the JID symbol. Use `jabber-avatar-set' to set it. ;;; Code: (require 'mailcap) (eval-when-compile (require 'cl)) ;;;; Variables (defgroup jabber-avatar nil "Avatar related settings" :group 'jabber) (defcustom jabber-avatar-cache-directory "~/.jabber-avatars/" "Directory to use for cached avatars" :group 'jabber-avatar :type 'directory) (defcustom jabber-avatar-verbose nil "Display messages about irregularities with other people's avatars." :group 'jabber-avatar :type 'boolean) ;;;; Avatar data handling (defstruct avatar sha1-sum mime-type url base64-data height width bytes) (defun jabber-avatar-from-url (url) "Construct an avatar structure from the given URL. Retrieves the image to find info about it." (with-current-buffer (let ((coding-system-for-read 'binary)) (url-retrieve-synchronously url)) (let* ((case-fold-search t) (mime-type (ignore-errors (search-forward-regexp "^content-type:[ \t]*\\(.*\\)$") (match-string 1))) (data (progn (search-forward "\n\n") (buffer-substring (point) (point-max))))) (prog1 (jabber-avatar-from-data data nil mime-type) (kill-buffer nil))))) (defun jabber-avatar-from-file (filename) "Construct an avatar structure from FILENAME." (require 'mailcap) (let ((data (with-temp-buffer (insert-file-contents-literally filename) (buffer-string))) (mime-type (when (string-match "\\.[^.]+$" filename) (mailcap-extension-to-mime (match-string 0 filename))))) (jabber-avatar-from-data data nil mime-type))) (defun jabber-avatar-from-base64-string (base64-string &optional mime-type) "Construct an avatar stucture from BASE64-STRING. If MIME-TYPE is not specified, try to find it from the image data." (jabber-avatar-from-data nil base64-string mime-type)) (defun jabber-avatar-from-data (raw-data base64-string &optional mime-type) "Construct an avatar structure from RAW-DATA and/or BASE64-STRING. If either is not provided, it is computed. If MIME-TYPE is not specified, try to find it from the image data." (let* ((data (or raw-data (base64-decode-string base64-string))) (bytes (length data)) (sha1-sum (sha1 data)) (base64-data (or base64-string (base64-encode-string raw-data))) (type (or mime-type (cdr (assq (get :type (cdr (create-image data nil t))) '((png "image/png") (jpeg "image/jpeg") (gif "image/gif"))))))) (jabber-avatar-compute-size (make-avatar :mime-type mime-type :sha1-sum sha1-sum :base64-data base64-data :bytes bytes)))) ;; XXX: This function is based on an outdated version of JEP-0084. ;; (defun jabber-avatar-from-data-node (data-node) ;; "Construct an avatar structure from the given node." ;; (jabber-xml-let-attributes ;; (content-type id bytes height width) data-node ;; (let ((base64-data (car (jabber-xml-node-children data-node)))) ;; (make-avatar :mime-type content-type :sha1-sum id :bytes bytes ;; :height height :width width :base64-data base64-data)))) (defun jabber-avatar-image (avatar) "Create an image from AVATAR. Return nil if images of this type are not supported." (create-image (with-temp-buffer (set-buffer-multibyte nil) (insert (avatar-base64-data avatar)) (base64-decode-region (point-min) (point-max)) (buffer-string)) nil t)) (defun jabber-avatar-compute-size (avatar) "Compute and set the width and height fields of AVATAR. Return AVATAR." ;; image-size only works when there is a window system. ;; But display-graphic-p doesn't exist on XEmacs... (let ((size (and (fboundp 'display-graphic-p) (display-graphic-p) (let ((image (jabber-avatar-image avatar))) (and image (image-size image t)))))) (when size (setf (avatar-width avatar) (car size)) (setf (avatar-height avatar) (cdr size))) avatar)) ;;;; Avatar cache (defun jabber-avatar-find-cached (sha1-sum) "Return file name of cached image for avatar identified by SHA1-SUM. If there is no cached image, return nil." ;; XXX: file-expand-wildcards doesn't exist in XEmacs (car (file-expand-wildcards (concat (file-name-as-directory jabber-avatar-cache-directory) sha1-sum ".*")))) (defun jabber-avatar-cache (avatar) "Cache the AVATAR." (let* ((id (avatar-sha1-sum avatar)) (base64-data (avatar-base64-data avatar)) (mime-type (avatar-mime-type avatar)) (extension (cond ((string= mime-type "image/png") ".png") ((string= mime-type "image/jpeg") ".jpg") ((string= mime-type "image/gif") ".gif") (t ".dat"))) (filename (expand-file-name (concat id extension) jabber-avatar-cache-directory)) (buffer (create-file-buffer filename))) (unless (file-directory-p jabber-avatar-cache-directory) (make-directory jabber-avatar-cache-directory)) (if (file-exists-p filename) (when jabber-avatar-verbose (message "Caching avatar, but %s already exists" filename)) (with-current-buffer buffer (let ((require-final-newline nil)) (setq buffer-file-coding-system 'binary) (if (fboundp 'set-buffer-multibyte) (set-buffer-multibyte nil)) (set-visited-file-name filename t) (insert base64-data) (base64-decode-region (point-min) (point-max)) (basic-save-buffer)))) (kill-buffer buffer))) ;;;; Set avatar for contact (defun jabber-avatar-set (jid avatar) "Set the avatar of JID to be AVATAR. JID is a string containing a bare JID. AVATAR may be one of: * An avatar structure. * The SHA1 sum of a cached avatar. * nil, meaning no avatar." ;; We want to optimize for the case of same avatar. ;; Loading an image is expensive, so do it lazily. (let ((jid-symbol (jabber-jid-symbol jid)) image hash) (cond ((avatar-p avatar) (setq hash (avatar-sha1-sum avatar)) (setq image (lambda () (jabber-avatar-image avatar)))) ((stringp avatar) (setq hash avatar) (setq image (lambda () (create-image (jabber-avatar-find-cached avatar))))) (t (setq hash nil) (setq image #'ignore))) (unless (string= hash (get jid-symbol 'avatar-hash)) (put jid-symbol 'avatar (funcall image)) (put jid-symbol 'avatar-hash hash) (jabber-presence-update-roster jid-symbol)))) (provide 'jabber-avatar) ;; arch-tag: 2405c3f8-8eaa-11da-826c-000a95c2fcd0 emacs-jabber-0.8.0/jabber-awesome.el0000644000175100017510000000304011250455034014156 00000000000000;; jabber-awesome.el - emacs-jabber interface to awesome and naughty ;; Copyright (C) 2009 - Evgenii Terechkov - evg@altlinux.org ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'jabber-alert)) (defcustom jabber-awesome-args ", timeout=5" "Additional args to naughty." :type 'string :group 'jabber-alerts) (defun jabber-awesome-message (msg) "Show MSG in Awesome" ;; Possible errors include not finding the awesome binary. (condition-case e (let ((process-connection-type)) (shell-command-to-string (format "echo 'naughty.notify({text = \"%s\" %s})' | awesome-client -" msg jabber-awesome-args)) ) (error nil))) (define-jabber-alert awesome "Show a message through the Awesome window manager" 'jabber-awesome-message) (define-personal-jabber-alert jabber-muc-awesome) (provide 'jabber-awesome) emacs-jabber-0.8.0/jabber-bookmarks.el0000644000175100017510000002161211133727374014524 00000000000000;; jabber-bookmarks.el - bookmarks according to XEP-0048 ;; Copyright (C) 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-private) (require 'jabber-widget) (require 'jabber-autoloads) (require 'cl) (defvar jabber-bookmarks (make-hash-table :test 'equal) "Mapping from full JIDs to bookmarks. Bookmarks are what has been retrieved from the server, as list of XML elements. This is nil if bookmarks have not been retrieved, and t if no bookmarks where found.") ;;;###autoload (defun jabber-get-conference-data (jc conference-jid cont &optional key) "Get bookmark data for CONFERENCE-JID. KEY may be nil or one of :name, :autojoin, :nick and :password. If KEY is nil, a plist containing the above keys is returned. CONT is called when the result is available, with JC and the result as arguments. If CONT is nil, return the requested data immediately, and return nil if it is not in the cache." (if (null cont) (let ((cache (jabber-get-bookmarks-from-cache jc))) (if (and cache (listp cache)) (jabber-get-conference-data-internal cache conference-jid key))) (jabber-get-bookmarks jc (lexical-let ((conference-jid conference-jid) (key key) (cont cont)) (lambda (jc result) (let ((entry (jabber-get-conference-data-internal result conference-jid key))) (funcall cont jc entry))))))) (defun jabber-get-conference-data-internal (result conference-jid key) (let ((entry (dolist (node result) (when (and (eq (jabber-xml-node-name node) 'conference) (string= (jabber-xml-get-attribute node 'jid) conference-jid)) (return (jabber-parse-conference-bookmark node)))))) (if key (plist-get entry key) entry))) ;;;###autoload (defun jabber-parse-conference-bookmark (node) "Convert a tag into a plist. The plist may contain the keys :jid, :name, :autojoin, :nick and :password." (when (eq (jabber-xml-node-name node) 'conference) (list :jid (jabber-xml-get-attribute node 'jid) :name (jabber-xml-get-attribute node 'name) :autojoin (member (jabber-xml-get-attribute node 'autojoin) '("true" "1")) :nick (car (jabber-xml-node-children (car (jabber-xml-get-children node 'nick)))) :password (car (jabber-xml-node-children (car (jabber-xml-get-children node 'password))))))) ;;;###autoload (defun jabber-get-bookmarks (jc cont &optional refresh) "Retrieve bookmarks (if needed) and call CONT. Arguments to CONT are JC and the bookmark list. CONT will be called as the result of a filter function or a timer. If REFRESH is non-nil, always fetch bookmarks." (let ((bookmarks (gethash (jabber-connection-bare-jid jc) jabber-bookmarks))) (if (and (not refresh) bookmarks) (run-with-timer 0 nil cont jc (when (listp bookmarks) bookmarks)) (lexical-let* ((cont cont) (callback (lambda (jc result) (jabber-get-bookmarks-1 jc result cont)))) (jabber-private-get jc 'storage "storage:bookmarks" callback callback))))) (defun jabber-get-bookmarks-1 (jc result cont) (let ((my-jid (jabber-connection-bare-jid jc)) (value (if (eq (jabber-xml-node-name result) 'storage) (or (jabber-xml-node-children result) t) t))) (puthash my-jid value jabber-bookmarks) (funcall cont jc (when (listp value) value)))) ;;;###autoload (defun jabber-get-bookmarks-from-cache (jc) "Return cached bookmarks for JC. If bookmarks have not yet been fetched by `jabber-get-bookmarks', return nil." (gethash (jabber-connection-bare-jid jc) jabber-bookmarks)) (defun jabber-set-bookmarks (jc bookmarks &optional callback) "Set bookmarks to BOOKMARKS, which is a list of XML elements. If CALLBACK is non-nil, call it with JC and t or nil as arguments on success or failure, respectively." (unless callback (setq callback #'ignore)) (jabber-private-set jc `(storage ((xmlns . "storage:bookmarks")) ,@bookmarks) callback t callback nil)) ;;;###autoload (defun jabber-edit-bookmarks (jc) "Create a buffer for editing bookmarks interactively." (interactive (list (jabber-read-account))) (jabber-get-bookmarks jc 'jabber-edit-bookmarks-1 t)) (defun jabber-edit-bookmarks-1 (jc bookmarks) (setq bookmarks (mapcar (lambda (e) (case (jabber-xml-node-name e) (url (list 'url (or (jabber-xml-get-attribute e 'url) "") (or (jabber-xml-get-attribute e 'name) ""))) (conference (list 'conference (or (jabber-xml-get-attribute e 'jid) "") (or (jabber-xml-get-attribute e 'name) "") (not (not (member (jabber-xml-get-attribute e 'autojoin) '("true" "1")))) (or (jabber-xml-path e '(nick "")) "") (or (jabber-xml-path e '(password "")) ""))))) bookmarks)) (setq bookmarks (delq nil bookmarks)) (with-current-buffer (get-buffer-create "Edit bookmarks") (jabber-init-widget-buffer nil) (setq jabber-buffer-connection jc) (widget-insert (jabber-propertize (concat "Edit bookmarks for " (jabber-connection-bare-jid jc)) 'face 'jabber-title-large) "\n\n") (when (or (bound-and-true-p jabber-muc-autojoin) (bound-and-true-p jabber-muc-default-nicknames)) (widget-insert "The variables `jabber-muc-autojoin' and/or `jabber-muc-default-nicknames'\n" "contain values. They are only available to jabber.el on this machine.\n" "You may want to import them into your bookmarks, to make them available\n" "to any client on any machine.\n") (widget-create 'push-button :notify 'jabber-bookmarks-import "Import values from variables") (widget-insert "\n\n")) (push (cons 'bookmarks (widget-create '(repeat :tag "Bookmarks" (choice (list :tag "Conference" (const :format "" conference) (string :tag "JID") ;XXX: jid widget type? (string :tag "Name") (checkbox :tag "Autojoin" :format "%[%v%] Autojoin?\n") (string :tag "Nick") ;or nil? (string :tag "Password") ;or nil? ) (list :tag "URL" (const :format "" url) (string :tag "URL") (string :tag "Name")))) :value bookmarks)) jabber-widget-alist) (widget-insert "\n") (widget-create 'push-button :notify 'jabber-bookmarks-submit "Submit") (widget-setup) (widget-minor-mode 1) (switch-to-buffer (current-buffer)) (goto-char (point-min)))) (defun jabber-bookmarks-submit (&rest ignore) (let ((bookmarks (widget-value (cdr (assq 'bookmarks jabber-widget-alist))))) (setq bookmarks (mapcar (lambda (entry) (case (car entry) (url (destructuring-bind (symbol url name) entry `(url ((url . ,url) (name . ,name))))) (conference (destructuring-bind (symbol jid name autojoin nick password) entry `(conference ((jid . ,jid) (name . ,name) (autojoin . ,(if autojoin "1" "0"))) ,@(unless (zerop (length nick)) `((nick () ,nick))) ,@(unless (zerop (length password)) `((password () ,password)))))))) bookmarks)) (remhash (jabber-connection-bare-jid jabber-buffer-connection) jabber-bookmarks) (jabber-private-set jabber-buffer-connection `(storage ((xmlns . "storage:bookmarks")) ,@bookmarks) 'jabber-report-success "Storing bookmarks" 'jabber-report-success "Storing bookmarks"))) (defun jabber-bookmarks-import (&rest ignore) (let* ((value (widget-value (cdr (assq 'bookmarks jabber-widget-alist)))) (conferences (mapcar 'cdr (remove-if-not (lambda (entry) (eq (car entry) 'conference)) value)))) (dolist (default-nickname jabber-muc-default-nicknames) (destructuring-bind (muc-jid . nick) default-nickname (let ((entry (assoc muc-jid conferences))) (if entry (setf (fourth entry) nick) (setq entry (list muc-jid "" nil nick "")) (push entry conferences) (push (cons 'conference entry) value))))) (dolist (autojoin jabber-muc-autojoin) (let ((entry (assoc autojoin conferences))) (if entry (setf (third entry) t) (setq entry (list autojoin "" t "" "")) (push (cons 'conference entry) value)))) (widget-value-set (cdr (assq 'bookmarks jabber-widget-alist)) value) (widget-setup))) (provide 'jabber-bookmarks) ;; arch-tag: a7d6f862-bac0-11db-831f-000a95c2fcd0 emacs-jabber-0.8.0/jabber-browse.el0000644000175100017510000000734611133727374014045 00000000000000;; jabber-browse.el - jabber browsing by JEP-0011 ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; Copyright (C) 2003, 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-iq) (require 'jabber-xml) (require 'jabber-util) ;; jabber.el can perform browse requests, but will not answer them. (add-to-list 'jabber-jid-info-menu (cons "Send browse query" 'jabber-get-browse)) (defun jabber-get-browse (jc to) "send a browse infoquery request to someone" (interactive (list (jabber-read-account) (jabber-read-jid-completing "browse: "))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:browse"))) #'jabber-process-data #'jabber-process-browse #'jabber-process-data "Browse failed")) ;; called from jabber-process-data (defun jabber-process-browse (jc xml-data) "Handle results from jabber:iq:browse requests." (dolist (item (jabber-xml-node-children xml-data)) (when (and (listp item) (not (eq (jabber-xml-node-name item) 'ns))) (let ((jid (jabber-xml-get-attribute item 'jid)) (beginning (point))) (cond ((or (eq (jabber-xml-node-name item) 'user) (string= (jabber-xml-get-attribute item 'category) "user")) (insert (jabber-propertize "$ USER" 'face 'jabber-title-medium) "\n\n")) ((or (eq (jabber-xml-node-name item) 'service) (string= (jabber-xml-get-attribute item 'category) "service")) (insert (jabber-propertize "* SERVICE" 'face 'jabber-title-medium) "\n\n")) ((or (eq (jabber-xml-node-name item) 'conference) (string= (jabber-xml-get-attribute item 'category) "conference")) (insert (jabber-propertize "@ CONFERENCE" 'face 'jabber-title-medium) "\n\n")) (t ;; So far I've seen "server" and "directory", both in the node-name. ;; Those are actually service disco categories, but jabberd 2 seems ;; to use them for browse results as well. It's not right (as in ;; JEP-0011), but it's reasonable. (let ((category (jabber-xml-get-attribute item 'category))) (if (= (length category) 0) (setq category (jabber-xml-node-name item))) (insert (jabber-propertize (format "! OTHER: %s" category) 'face 'jabber-title-medium) "\n\n")))) (dolist (attr '((type . "Type:\t\t") (jid . "JID:\t\t") (name . "Name:\t\t") (version . "Version:\t"))) (let ((data (jabber-xml-get-attribute item (car attr)))) (if (> (length data) 0) (insert (cdr attr) data "\n")))) (dolist (ns (jabber-xml-get-children item 'ns)) (if (stringp (car (jabber-xml-node-children ns))) (insert "Namespace:\t" (car (jabber-xml-node-children ns)) "\n"))) (insert "\n") (put-text-property beginning (point) 'jabber-jid jid) (put-text-property beginning (point) 'jabber-account jc) ;; XXX: Is this kind of recursion really needed? (if (listp (car (jabber-xml-node-children item))) (jabber-process-browse jc item)))))) (provide 'jabber-browse) ;;; arch-tag: be01ab34-96eb-4fcb-aa35-a0d3e6c446c3 emacs-jabber-0.8.0/jabber-chat.el0000644000175100017510000005754011250455045013455 00000000000000;; jabber-chat.el - one-to-one chats ;; Copyright (C) 2005, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-core) (require 'jabber-chatbuffer) (require 'jabber-history) (require 'jabber-autoloads) (require 'jabber-menu) ;we need jabber-jid-chat-menu (require 'ewoc) (eval-when-compile (require 'cl)) (defgroup jabber-chat nil "chat display options" :group 'jabber) (defcustom jabber-chat-buffer-format "*-jabber-chat-%n-*" "The format specification for the name of chat buffers. These fields are available (all are about the person you are chatting with): %n Nickname, or JID if no nickname set %j Bare JID (without resource) %r Resource" :type 'string :group 'jabber-chat) (defcustom jabber-chat-header-line-format '("" (jabber-chat-buffer-show-avatar (:eval (let ((buddy (jabber-jid-symbol jabber-chatting-with))) (jabber-propertize " " 'display (get buddy 'avatar))))) (:eval (jabber-jid-displayname jabber-chatting-with)) "\t" (:eval (let ((buddy (jabber-jid-symbol jabber-chatting-with))) (propertize (or (cdr (assoc (get buddy 'show) jabber-presence-strings)) (get buddy 'show)) 'face (or (cdr (assoc (get buddy 'show) jabber-presence-faces)) 'jabber-roster-user-online)))) "\t" (:eval (jabber-fix-status (get (jabber-jid-symbol jabber-chatting-with) 'status))) "\t" jabber-events-message ;see jabber-events.el "\t" jabber-chatstates-message) ;see jabber-chatstates.el "The specification for the header line of chat buffers. The format is that of `mode-line-format' and `header-line-format'." :type 'sexp :group 'jabber-chat) (defcustom jabber-chat-buffer-show-avatar t "Show avatars in header line of chat buffer? This variable might not take effect if you have changed `jabber-chat-header-line-format'." :type 'boolean :group 'jabber-chat) (defcustom jabber-chat-time-format "%H:%M" "The format specification for instant messages in the chat buffer. See also `jabber-chat-delayed-time-format'. See `format-time-string' for valid values." :type 'string :group 'jabber-chat) (defcustom jabber-chat-delayed-time-format "%Y-%m-%d %H:%M" "The format specification for delayed messages in the chat buffer. See also `jabber-chat-time-format'. See `format-time-string' for valid values." :type 'string :group 'jabber-chat) (defcustom jabber-print-rare-time t "Non-nil means to print \"rare time\" indications in chat buffers. The default settings tell every new hour." :type 'boolean :group 'jabber-chat) (defcustom jabber-rare-time-format "%a %e %b %Y %H:00" "The format specification for the rare time information. Rare time information will be printed whenever the current time, formatted according to this string, is different to the last rare time printed." :type 'string :group 'jabber-chat) (defface jabber-rare-time-face '((t (:foreground "darkgreen" :underline t))) "face for displaying the rare time info" :group 'jabber-chat) (defcustom jabber-chat-local-prompt-format "[%t] %n> " "The format specification for lines you type in the chat buffer. These fields are available: %t Time, formatted according to `jabber-chat-time-format' or `jabber-chat-delayed-time-format' %u Username %n Nickname (obsolete, same as username) %r Resource %j Bare JID (without resource)" :type 'string :group 'jabber-chat) (defcustom jabber-chat-foreign-prompt-format "[%t] %n> " "The format specification for lines others type in the chat buffer. These fields are available: %t Time, formatted according to `jabber-chat-time-format' or `jabber-chat-delayed-time-format' %n Nickname, or JID if no nickname set %u Username %r Resource %j Bare JID (without resource)" :type 'string :group 'jabber-chat) (defcustom jabber-chat-system-prompt-format "[%t] *** " "The format specification for lines from the system or that are special in the chat buffer." :type 'string :group 'jabber-chat) (defface jabber-chat-prompt-local '((t (:foreground "blue" :weight bold))) "face for displaying the chat prompt for what you type in" :group 'jabber-chat) (defface jabber-chat-prompt-foreign '((t (:foreground "red" :weight bold))) "face for displaying the chat prompt for what they send" :group 'jabber-chat) (defface jabber-chat-prompt-system '((t (:foreground "green" :weight bold))) "face used for system and special messages" :group 'jabber-chat) (defface jabber-chat-text-local '((t ())) "Face used for text you write" :group 'jabber-chat) (defface jabber-chat-text-foreign '((t ())) "Face used for text others write" :group 'jabber-chat) (defface jabber-chat-error '((t (:foreground "red" :weight bold))) "Face used for error messages" :group 'jabber-chat) ;;;###autoload (defvar jabber-chatting-with nil "JID of the person you are chatting with") (defvar jabber-chat-printers '(jabber-chat-print-subject jabber-chat-print-body jabber-chat-print-url jabber-chat-goto-address) "List of functions that may be able to print part of a message. Each function receives these arguments: XML-DATA The entire message stanza WHO :local or :foreign, for sent or received stanza, respectively MODE :insert or :printp. For :insert, insert text at point. For :printp, return non-nil if function would insert text.") (defvar jabber-body-printers '(jabber-chat-normal-body) "List of functions that may be able to print a body for a message. Each function receives these arguments: XML-DATA The entire message stanza WHO :local, :foreign or :error MODE :insert or :printp. For :insert, insert text at point. For :printp, return non-nil if function would insert text. These functions are called in order, until one of them returns non-nil. Add a function to the beginning of this list if the tag it handles replaces the contents of the tag.") (defvar jabber-chat-send-hooks nil "List of functions called when a chat message is sent. The arguments are the text to send, and the id attribute of the message. The functions should return a list of XML nodes they want to be added to the outgoing message.") (defvar jabber-chat-earliest-backlog nil "Float-time of earliest backlog entry inserted into buffer. nil if no backlog has been inserted.") ;;;###autoload (defun jabber-chat-get-buffer (chat-with) "Return the chat buffer for chatting with CHAT-WITH (bare or full JID). Either a string or a buffer is returned, so use `get-buffer' or `get-buffer-create'." (format-spec jabber-chat-buffer-format (list (cons ?n (jabber-jid-displayname chat-with)) (cons ?j (jabber-jid-user chat-with)) (cons ?r (or (jabber-jid-resource chat-with) ""))))) (defun jabber-chat-create-buffer (jc chat-with) "Prepare a buffer for chatting with CHAT-WITH. This function is idempotent." (with-current-buffer (get-buffer-create (jabber-chat-get-buffer chat-with)) (unless (eq major-mode 'jabber-chat-mode) (jabber-chat-mode jc #'jabber-chat-pp)) ;; Make sure the connection variable is up to date. (setq jabber-buffer-connection jc) (make-local-variable 'jabber-chatting-with) (setq jabber-chatting-with chat-with) (setq jabber-send-function 'jabber-chat-send) (setq header-line-format jabber-chat-header-line-format) (make-local-variable 'jabber-chat-earliest-backlog) ;; insert backlog (when (null jabber-chat-earliest-backlog) (let ((backlog-entries (jabber-history-backlog chat-with))) (if (null backlog-entries) (setq jabber-chat-earliest-backlog (jabber-float-time)) (setq jabber-chat-earliest-backlog (jabber-float-time (jabber-parse-time (aref (car backlog-entries) 0)))) (mapc 'jabber-chat-insert-backlog-entry (nreverse backlog-entries))))) (current-buffer))) (defun jabber-chat-insert-backlog-entry (msg) "Insert backlog entry MSG at beginning of buffer." ;; Rare timestamps are especially important in backlog. We risk ;; having superfluous timestamps if we just add before each backlog ;; entry. (let* ((message-time (jabber-parse-time (aref msg 0))) (fake-stanza `(message ((from . ,(aref msg 2))) (body nil ,(aref msg 4)) (x ((xmlns . "jabber:x:delay") (stamp . ,(jabber-encode-legacy-time message-time)))))) (node-data (list (if (string= (aref msg 1) "in") :foreign :local) fake-stanza :delayed t))) ;; Insert after existing rare timestamp? (if (and jabber-print-rare-time (ewoc-nth jabber-chat-ewoc 0) (eq (car (ewoc-data (ewoc-nth jabber-chat-ewoc 0))) :rare-time) (not (jabber-rare-time-needed message-time (cadr (ewoc-data (ewoc-nth jabber-chat-ewoc 0)))))) (ewoc-enter-after jabber-chat-ewoc (ewoc-nth jabber-chat-ewoc 0) node-data) ;; Insert first. (ewoc-enter-first jabber-chat-ewoc node-data) (when jabber-print-rare-time (ewoc-enter-first jabber-chat-ewoc (list :rare-time message-time)))))) (add-to-list 'jabber-jid-chat-menu (cons "Display more context" 'jabber-chat-display-more-backlog)) (defun jabber-chat-display-more-backlog (how-many) (interactive "nHow many more messages? ") (let* ((inhibit-read-only t) (jabber-backlog-days nil) (jabber-backlog-number how-many) (backlog-entries (jabber-history-backlog jabber-chatting-with jabber-chat-earliest-backlog))) (when backlog-entries (setq jabber-chat-earliest-backlog (jabber-float-time (jabber-parse-time (aref (car backlog-entries) 0)))) (save-excursion (goto-char (point-min)) (mapc 'jabber-chat-insert-backlog-entry (nreverse backlog-entries)))))) (add-to-list 'jabber-message-chain 'jabber-process-chat) (defun jabber-process-chat (jc xml-data) "If XML-DATA is a one-to-one chat message, handle it as such." ;; For now, everything that is not a public MUC message is ;; potentially a 1to1 chat message. (when (not (jabber-muc-message-p xml-data)) ;; Note that we handle private MUC messages here. (let ((from (jabber-xml-get-attribute xml-data 'from)) (error-p (jabber-xml-get-children xml-data 'error)) (body-text (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'body)))))) ;; First check if we would output anything for this stanza. (when (or error-p (run-hook-with-args-until-success 'jabber-chat-printers xml-data :foreign :printp)) ;; If so, create chat buffer, if necessary... (with-current-buffer (if (jabber-muc-sender-p from) (jabber-muc-private-create-buffer jc (jabber-jid-user from) (jabber-jid-resource from)) (jabber-chat-create-buffer jc from)) ;; ...add the message to the ewoc... (let ((node (ewoc-enter-last jabber-chat-ewoc (list (if error-p :error :foreign) xml-data :time (current-time))))) (jabber-maybe-print-rare-time node)) ;; ...and call alert hooks. (dolist (hook '(jabber-message-hooks jabber-alert-message-hooks)) (run-hook-with-args hook from (current-buffer) body-text (funcall jabber-alert-message-function from (current-buffer) body-text)))))))) (defun jabber-chat-send (jc body) "Send BODY through connection JC, and display it in chat buffer." ;; Build the stanza... (let* ((id (apply 'format "emacs-msg-%d.%d.%d" (current-time))) (stanza-to-send `(message ((to . ,jabber-chatting-with) (type . "chat") (id . ,id)) (body () ,body)))) ;; ...add additional elements... (dolist (hook jabber-chat-send-hooks) (nconc stanza-to-send (funcall hook body id))) ;; ...display it, if it would be displayed. (when (run-hook-with-args-until-success 'jabber-chat-printers stanza-to-send :local :printp) (jabber-maybe-print-rare-time (ewoc-enter-last jabber-chat-ewoc (list :local stanza-to-send :time (current-time))))) ;; ...and send it... (jabber-send-sexp jc stanza-to-send))) (defun jabber-chat-pp (data) "Pretty-print a stanza. \(car data) is either :local, :foreign, :error or :notice. \(cadr data) is the stanza. This function is used as an ewoc prettyprinter." (let* ((beg (point)) (original-timestamp (when (listp (cadr data)) (jabber-xml-path (cadr data) '(("jabber:x:delay" . "x"))))) (internal-time (plist-get (cddr data) :time)) (body (ignore-errors (car (jabber-xml-node-children (car (jabber-xml-get-children (cadr data) 'body)))))) (/me-p (and (> (length body) 4) (string= (substring body 0 4) "/me ")))) ;; Print prompt... (let ((delayed (or original-timestamp (plist-get (cddr data) :delayed)))) (case (car data) (:local (jabber-chat-self-prompt (or (jabber-x-delay original-timestamp) internal-time) delayed /me-p)) (:foreign ;; For :error and :notice, this might be a string... beware (jabber-chat-print-prompt (when (listp (cadr data)) (cadr data)) (or (jabber-x-delay original-timestamp) internal-time) delayed /me-p)) ((:error :notice :subscription-request) (jabber-chat-system-prompt (or (jabber-x-delay original-timestamp) internal-time))) (:muc-local (jabber-muc-print-prompt (cadr data) t /me-p)) (:muc-foreign (jabber-muc-print-prompt (cadr data) nil /me-p)) ((:muc-notice :muc-error) (jabber-muc-system-prompt)))) ;; ...and body (case (car data) ((:local :foreign) (run-hook-with-args 'jabber-chat-printers (cadr data) (car data) :insert)) ((:muc-local :muc-foreign) (let ((printers (append jabber-muc-printers jabber-chat-printers))) (run-hook-with-args 'printers (cadr data) (car data) :insert))) ((:error :muc-error) (if (stringp (cadr data)) (insert (jabber-propertize (cadr data) 'face 'jabber-chat-error)) (jabber-chat-print-error (cadr data)))) ((:notice :muc-notice) (insert (cadr data))) (:rare-time (insert (jabber-propertize (format-time-string jabber-rare-time-format (cadr data)) 'face 'jabber-rare-time-face))) (:subscription-request (insert "This user requests subscription to your presence.\n") (when (and (stringp (cadr data)) (not (zerop (length (cadr data))))) (insert "Message: " (cadr data) "\n")) (insert "Accept?\n\n") (flet ((button (text action) (if (fboundp 'insert-button) (insert-button text 'action action) ;; simple button replacement (let ((keymap (make-keymap))) (define-key keymap "\r" action) (insert (jabber-propertize text 'keymap keymap 'face 'highlight)))) (insert "\t"))) (button "Mutual" 'jabber-subscription-accept-mutual) (button "One-way" 'jabber-subscription-accept-one-way) (button "Decline" 'jabber-subscription-decline)))) (when jabber-chat-fill-long-lines (save-restriction (narrow-to-region beg (point)) (jabber-chat-buffer-fill-long-lines))) (put-text-property beg (point) 'read-only t) (put-text-property beg (point) 'front-sticky t) (put-text-property beg (point) 'rear-nonsticky t))) (defun jabber-rare-time-needed (time1 time2) "Return non-nil if a timestamp should be printed between TIME1 and TIME2." (not (string= (format-time-string jabber-rare-time-format time1) (format-time-string jabber-rare-time-format time2)))) (defun jabber-message-time (entry) "Return time of ENTRY, a message in internal format." (or (when (listp (cadr entry)) (jabber-x-delay (jabber-xml-path (cadr entry) '(("jabber:x:delay" . "x"))))) (plist-get (cddr entry) :time))) (defun jabber-maybe-print-rare-time (node) "Print rare time before NODE, if appropriate." (let* ((prev (ewoc-prev jabber-chat-ewoc node)) (data (ewoc-data node)) (prev-data (when prev (ewoc-data prev)))) (when (and jabber-print-rare-time (or (null prev) (jabber-rare-time-needed (jabber-message-time prev-data) (jabber-message-time data)))) (ewoc-enter-before jabber-chat-ewoc node (list :rare-time (jabber-message-time data)))))) (defun jabber-chat-print-prompt (xml-data timestamp delayed dont-print-nick-p) "Print prompt for received message in XML-DATA. TIMESTAMP is the timestamp to print, or nil to get it from a jabber:x:delay element. If DELAYED is true, print long timestamp \(`jabber-chat-delayed-time-format' as opposed to `jabber-chat-time-format'). If DONT-PRINT-NICK-P is true, don't include nickname." (let ((from (jabber-xml-get-attribute xml-data 'from)) (timestamp (or timestamp (car (delq nil (mapcar 'jabber-x-delay (jabber-xml-get-children xml-data 'x))))))) (insert (jabber-propertize (format-spec jabber-chat-foreign-prompt-format (list (cons ?t (format-time-string (if delayed jabber-chat-delayed-time-format jabber-chat-time-format) timestamp)) (cons ?n (if dont-print-nick-p "" (jabber-jid-displayname from))) (cons ?u (or (jabber-jid-username from) from)) (cons ?r (jabber-jid-resource from)) (cons ?j (jabber-jid-user from)))) 'face 'jabber-chat-prompt-foreign 'help-echo (concat (format-time-string "On %Y-%m-%d %H:%M:%S" timestamp) " from " from))))) (defun jabber-chat-system-prompt (timestamp) (insert (jabber-propertize (format-spec jabber-chat-foreign-prompt-format (list (cons ?t (format-time-string jabber-chat-time-format timestamp)) (cons ?n "") (cons ?u "") (cons ?r "") (cons ?j ""))) 'face 'jabber-chat-prompt-system 'help-echo (concat (format-time-string "System message on %Y-%m-%d %H:%M:%S" timestamp))))) (defun jabber-chat-self-prompt (timestamp delayed dont-print-nick-p) "Print prompt for sent message. TIMESTAMP is the timestamp to print, or nil for now. If DELAYED is true, print long timestamp \(`jabber-chat-delayed-time-format' as opposed to `jabber-chat-time-format'). If DONT-PRINT-NICK-P is true, don't include nickname." (let* ((state-data (fsm-get-state-data jabber-buffer-connection)) (username (plist-get state-data :username)) (server (plist-get state-data :server)) (resource (plist-get state-data :resource)) (nickname username)) (insert (jabber-propertize (format-spec jabber-chat-local-prompt-format (list (cons ?t (format-time-string (if delayed jabber-chat-delayed-time-format jabber-chat-time-format) timestamp)) (cons ?n (if dont-print-nick-p "" nickname)) (cons ?u username) (cons ?r resource) (cons ?j (concat username "@" server)))) 'face 'jabber-chat-prompt-local 'help-echo (concat (format-time-string "On %Y-%m-%d %H:%M:%S" timestamp) " from you"))))) (defun jabber-chat-print-error (xml-data) "Print error in given in a readable way." (let ((the-error (car (jabber-xml-get-children xml-data 'error)))) (insert (jabber-propertize (concat "Error: " (jabber-parse-error the-error)) 'face 'jabber-chat-error)))) (defun jabber-chat-print-subject (xml-data who mode) "Print subject of given , if any." (let ((subject (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'subject)))))) (when (not (zerop (length subject))) (case mode (:printp t) (:insert (insert (jabber-propertize "Subject: " 'face 'jabber-chat-prompt-system) (jabber-propertize subject 'face 'jabber-chat-text-foreign) "\n")))))) (defun jabber-chat-print-body (xml-data who mode) (run-hook-with-args-until-success 'jabber-body-printers xml-data who mode)) (defun jabber-chat-normal-body (xml-data who mode) "Print body for received message in XML-DATA." (let ((body (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'body)))))) (when body (when (eql mode :insert) (if (and (> (length body) 4) (string= (substring body 0 4) "/me ")) (let ((action (substring body 4)) (nick (cond ((eq who :local) (plist-get (fsm-get-state-data jabber-buffer-connection) :username)) ((jabber-muc-message-p xml-data) (jabber-jid-resource (jabber-xml-get-attribute xml-data 'from))) (t (jabber-jid-displayname (jabber-xml-get-attribute xml-data 'from)))))) (insert (jabber-propertize (concat nick " " action) 'face 'jabber-chat-prompt-system))) (insert (jabber-propertize body 'face (case who ((:foreign :muc-foreign) 'jabber-chat-text-foreign) ((:local :muc-local) 'jabber-chat-text-local)))))) t))) (defun jabber-chat-print-url (xml-data who mode) "Print URLs provided in jabber:x:oob namespace." (let ((foundp nil)) (dolist (x (jabber-xml-node-children xml-data)) (when (and (listp x) (eq (jabber-xml-node-name x) 'x) (string= (jabber-xml-get-attribute x 'xmlns) "jabber:x:oob")) (setq foundp t) (when (eql mode :insert) (let ((url (car (jabber-xml-node-children (car (jabber-xml-get-children x 'url))))) (desc (car (jabber-xml-node-children (car (jabber-xml-get-children x 'desc)))))) (insert "\n" (jabber-propertize "URL: " 'face 'jabber-chat-prompt-system) (format "%s <%s>" desc url)))))) foundp)) (defun jabber-chat-goto-address (xml-data who mode) "Call `goto-address' on the newly written text." (when (eq mode :insert) (ignore-errors (goto-address)))) ;; jabber-compose is autoloaded in jabber.el (add-to-list 'jabber-jid-chat-menu (cons "Compose message" 'jabber-compose)) (defun jabber-send-message (jc to subject body type) "send a message tag to the server" (interactive (list (jabber-read-account) (jabber-read-jid-completing "to: ") (jabber-read-with-input-method "subject: ") (jabber-read-with-input-method "body: ") (read-string "type: "))) (jabber-send-sexp jc `(message ((to . ,to) ,(if (> (length type) 0) `(type . ,type))) ,(if (> (length subject) 0) `(subject () ,subject)) ,(if (> (length body) 0) `(body () ,body)))) (if (and jabber-history-enabled (not (string= type "groupchat"))) (jabber-history-log-message "out" nil to body (current-time)))) (add-to-list 'jabber-jid-chat-menu (cons "Start chat" 'jabber-chat-with)) (defun jabber-chat-with (jc jid &optional other-window) "Open an empty chat window for chatting with JID. With a prefix argument, open buffer in other window. Returns the chat buffer." (interactive (let ((jid (jabber-read-jid-completing "chat with:")) (account (jabber-read-account))) (list account jid current-prefix-arg))) (let ((buffer (jabber-chat-create-buffer jc jid))) (if other-window (switch-to-buffer-other-window buffer) (switch-to-buffer buffer)))) (defun jabber-chat-with-jid-at-point (&optional other-window) "Start chat with JID at point. Signal an error if there is no JID at point. With a prefix argument, open buffer in other window." (interactive "P") (let ((jid-at-point (get-text-property (point) 'jabber-jid)) (account (get-text-property (point) 'jabber-account))) (if (and jid-at-point account) (jabber-chat-with account jid-at-point other-window) (error "No contact at point")))) (provide 'jabber-chat) ;; arch-tag: f423eb92-aa87-475b-b590-48c93ccba9be emacs-jabber-0.8.0/jabber-chatbuffer.el0000644000175100017510000001126511133727374014650 00000000000000;; jabber-chatbuffer.el - functions common to all chat buffers ;; Copyright (C) 2005, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-keymap) (defvar jabber-point-insert nil "Position where the message being composed starts") (defvar jabber-send-function nil "Function for sending a message from a chat buffer.") (defvar jabber-chat-mode-hook nil "Hook called at the end of `jabber-chat-mode'. Note that functions in this hook have no way of knowing what kind of chat buffer is being created.") (defcustom jabber-chat-fill-long-lines t "If non-nil, fill long lines in chat buffers. Lines are broken at word boundaries at the width of the window or at `fill-column', whichever is shorter." :group 'jabber-chat :type 'boolean) (defvar jabber-chat-ewoc nil "The ewoc showing the messages of this chat buffer.") ;;;###autoload (defvar jabber-buffer-connection nil "The connection used by this buffer.") ;;;###autoload (make-variable-buffer-local 'jabber-buffer-connection) (defun jabber-chat-mode (jc ewoc-pp) "\\{jabber-chat-mode-map}" (kill-all-local-variables) ;; Make sure to set this variable somewhere (make-local-variable 'jabber-send-function) (setq jabber-buffer-connection jc) (make-local-variable 'scroll-conservatively) (setq scroll-conservatively 5) (make-local-variable 'jabber-point-insert) (make-local-variable 'jabber-chat-ewoc) (unless jabber-chat-ewoc (setq jabber-chat-ewoc (ewoc-create ewoc-pp nil "---")) (goto-char (point-max)) (put-text-property (point-min) (point) 'read-only t) (let ((inhibit-read-only t)) (put-text-property (point-min) (point) 'front-sticky t) (put-text-property (point-min) (point) 'rear-nonsticky t)) (setq jabber-point-insert (point-marker))) ;;(setq header-line-format jabber-chat-header-line-format) (setq major-mode 'jabber-chat-mode mode-name "jabber-chat") (use-local-map jabber-chat-mode-map) (if (fboundp 'run-mode-hooks) (run-mode-hooks 'jabber-chat-mode-hook) (run-hooks 'jabber-chat-mode-hook))) (put 'jabber-chat-mode 'mode-class 'special) ;; Spell check only what you're currently writing (defun jabber-chat-mode-flyspell-verify () (>= (point) jabber-point-insert)) (put 'jabber-chat-mode 'flyspell-mode-predicate 'jabber-chat-mode-flyspell-verify) (defvar jabber-chat-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map jabber-common-keymap) (define-key map "\r" 'jabber-chat-buffer-send) map)) (defun jabber-chat-buffer-send () (interactive) ;; If user accidentally hits RET without writing anything, just ;; ignore it. (when (plusp (- (point-max) jabber-point-insert)) ;; If connection was lost... (unless (memq jabber-buffer-connection jabber-connections) ;; ...maybe there is a new connection to the same account. (let ((new-jc (jabber-find-active-connection jabber-buffer-connection))) (if new-jc ;; If so, just use it. (setq jabber-buffer-connection new-jc) ;; Otherwise, ask for a new account. (setq jabber-buffer-connection (jabber-read-account t))))) (let ((body (delete-and-extract-region jabber-point-insert (point-max)))) (funcall jabber-send-function jabber-buffer-connection body)))) (defun jabber-chat-buffer-fill-long-lines () "Fill lines that are wider than the window width." ;; This was mostly stolen from article-fill-long-lines (interactive) (save-excursion (let ((inhibit-read-only t) (width (window-width (get-buffer-window (current-buffer))))) (goto-char (point-min)) (let ((adaptive-fill-mode nil)) ;Why? -sm (while (not (eobp)) (end-of-line) (when (>= (current-column) (min fill-column width)) (save-restriction (narrow-to-region (min (1+ (point)) (point-max)) (point-at-bol)) (let ((goback (point-marker))) (fill-paragraph nil) (goto-char (marker-position goback))))) (forward-line 1)))))) (provide 'jabber-chatbuffer) ;; arch-tag: 917e5b60-5894-4c49-b3bc-12e1f97ffdc6 emacs-jabber-0.8.0/jabber-chatstates.el0000644000175100017510000001505311133727374014701 00000000000000;;; jabber-chatstate.el --- Chat state notification (XEP-0085) implementation ;; Author: Ami Fischman ;; (based entirely on jabber-events.el by Magnus Henoch ) ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;; TODO ;; - Currently only active/composing notifications are /sent/ though all 5 ;; notifications are handled on receipt. (require 'jabber-autoloads) (require 'cl) (defgroup jabber-chatstates nil "Chat state notifications." :group 'jabber) (defconst jabber-chatstates-xmlns "http://jabber.org/protocol/chatstates" "XML namespace for the chatstates feature.") (defcustom jabber-chatstates-confirm t "Send notifications about chat states?" :group 'jabber-chatstates :type 'boolean) (defvar jabber-chatstates-requested 'first-time "Whether or not chat states notification was requested. This is one of the following: first-time - send state in first stanza, then switch to nil t - send states nil - don't send states") (make-variable-buffer-local 'jabber-chatstates-requested) (defvar jabber-chatstates-last-state nil "The last seen chat state.") (make-variable-buffer-local 'jabber-chatstates-last-state) (defvar jabber-chatstates-message "" "Human-readable presentation of chat state information") (make-variable-buffer-local 'jabber-chatstates-message) ;;; INCOMING ;;; Code for requesting chat state notifications from others and handling ;;; them. (defun jabber-chatstates-update-message () (setq jabber-chatstates-message (if (and jabber-chatstates-last-state (not (eq 'active jabber-chatstates-last-state))) (format " (%s)" (symbol-name jabber-chatstates-last-state)) ""))) (add-hook 'jabber-chat-send-hooks 'jabber-chatstates-when-sending) (defun jabber-chatstates-when-sending (text id) (jabber-chatstates-update-message) (jabber-chatstates-stop-timer) (when (and jabber-chatstates-confirm jabber-chatstates-requested) (when (eq jabber-chatstates-requested 'first-time) ;; don't send more notifications until we know that the other ;; side wants them. (setq jabber-chatstates-requested nil)) `((active ((xmlns . ,jabber-chatstates-xmlns)))))) ;;; OUTGOING ;;; Code for handling requests for chat state notifications and providing ;;; them, modulo user preferences. (defvar jabber-chatstates-composing-sent nil "Has composing notification been sent? It can be sent and cancelled several times.") (make-variable-buffer-local 'jabber-chatstates-composing-sent) (defvar jabber-chatstates-paused-timer nil "Timer that counts down from 'composing state to 'paused.") (make-variable-buffer-local 'jabber-chatstates-paused-timer) (defun jabber-chatstates-stop-timer () "Stop the 'paused timer." (when jabber-chatstates-paused-timer (cancel-timer jabber-chatstates-paused-timer))) (defun jabber-chatstates-kick-timer () "Start (or restart) the 'paused timer as approriate." (jabber-chatstates-stop-timer) (setq jabber-chatstates-paused-timer (run-with-timer 5 nil 'jabber-chatstates-send-paused))) (defun jabber-chatstates-send-paused () "Send an 'paused state notification." (when (and jabber-chatstates-requested jabber-chatting-with) (setq jabber-chatstates-composing-sent nil) (jabber-send-sexp jabber-buffer-connection `(message ((to . ,jabber-chatting-with)) (paused ((xmlns . ,jabber-chatstates-xmlns))))))) (defun jabber-chatstates-after-change () (let* ((composing-now (not (= (point-max) jabber-point-insert))) (state (if composing-now 'composing 'active))) (when (and jabber-chatstates-confirm jabber-chatting-with jabber-chatstates-requested (not (eq composing-now jabber-chatstates-composing-sent))) (jabber-send-sexp jabber-buffer-connection `(message ((to . ,jabber-chatting-with)) (,state ((xmlns . ,jabber-chatstates-xmlns))))) (when (setq jabber-chatstates-composing-sent composing-now) (jabber-chatstates-kick-timer))))) ;;; COMMON (defun jabber-handle-incoming-message-chatstates (jc xml-data) (when (get-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from))) (with-current-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from)) (cond ;; If we get an error message, we shouldn't report any ;; events, as the requests are mirrored from us. ((string= (jabber-xml-get-attribute xml-data 'type) "error") (remove-hook 'post-command-hook 'jabber-chatstates-after-change t) (setq jabber-chatstates-requested nil)) (t (let ((state (or (let ((node (find jabber-chatstates-xmlns (jabber-xml-node-children xml-data) :key #'(lambda (x) (jabber-xml-get-attribute x 'xmlns)) :test #'string=))) (jabber-xml-node-name node)) (let ((node ;; XXX: this is how we interoperate with ;; Google Talk. We should really use a ;; namespace-aware XML parser. (find jabber-chatstates-xmlns (jabber-xml-node-children xml-data) :key #'(lambda (x) (jabber-xml-get-attribute x 'xmlns:cha)) :test #'string=))) (when node ;; Strip the "cha:" prefix (let ((name (symbol-name (jabber-xml-node-name node)))) (when (> (length name) 4) (intern (substring name 4))))))))) ;; Set up hooks for composition notification (when (and jabber-chatstates-confirm state) (setq jabber-chatstates-requested t) (add-hook 'post-command-hook 'jabber-chatstates-after-change nil t)) (setq jabber-chatstates-last-state state) (jabber-chatstates-update-message))))))) ;; Add function last in chain, so a chat buffer is already created. (add-to-list 'jabber-message-chain 'jabber-handle-incoming-message-chatstates t) (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/chatstates") (provide 'jabber-chatstates) ;; arch-tag: d879de90-51e1-11dc-909d-000a95c2fcd0 emacs-jabber-0.8.0/jabber-compose.el0000644000175100017510000000527111133727374014204 00000000000000;;; jabber-compose.el --- compose a Jabber message in a buffer ;; Copyright (C) 2006, 2007 Magnus Henoch ;; Author: Magnus Henoch ;; Keywords: ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Code: ;;;###autoload (defun jabber-compose (jc &optional recipient) "Create a buffer for composing a Jabber message." (interactive (list (jabber-read-account) (jabber-read-jid-completing "To whom? "))) (with-current-buffer (get-buffer-create (generate-new-buffer-name (concat "Jabber-Compose" (when recipient (format "-%s" (jabber-jid-displayname recipient)))))) (set (make-local-variable 'jabber-widget-alist) nil) (setq jabber-buffer-connection jc) (use-local-map widget-keymap) (insert (jabber-propertize "Compose Jabber message\n" 'face 'jabber-title-large)) (insert (substitute-command-keys "\\Completion available with \\[widget-complete].\n")) (push (cons :recipients (widget-create '(repeat :tag "Recipients" jid) :value (when recipient (list recipient)))) jabber-widget-alist) (insert "\nSubject: ") (push (cons :subject (widget-create 'editable-field :value "")) jabber-widget-alist) (insert "\nText:\n") (push (cons :text (widget-create 'text :value "")) jabber-widget-alist) (insert "\n") (widget-create 'push-button :notify #'jabber-compose-send "Send") (widget-setup) (switch-to-buffer (current-buffer)) (goto-char (point-min)))) (defun jabber-compose-send (&rest ignore) (let ((recipients (widget-value (cdr (assq :recipients jabber-widget-alist)))) (subject (widget-value (cdr (assq :subject jabber-widget-alist)))) (text (widget-value (cdr (assq :text jabber-widget-alist))))) (when (null recipients) (error "No recipients specified")) (dolist (to recipients) (jabber-send-message jabber-buffer-connection to subject text nil)) (bury-buffer) (message "Message sent"))) (provide 'jabber-compose) ;; arch-tag: 59032c00-994d-11da-8d97-000a95c2fcd0 emacs-jabber-0.8.0/jabber-conn.el0000644000175100017510000002137611133727374013500 00000000000000;; jabber-conn.el - Network transport functions ;; Copyright (C) 2005 - Georg Lehner - jorge@magma.com.ni ;; mostly inspired by Gnus. ;; Copyright (C) 2005 - Carl Henrik Lunde - chlunde+jabber+@ping.uio.no ;; (starttls) ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;; A collection of functions, that hide the details of transmitting to ;; and fro a Jabber Server (eval-when-compile (require 'cl)) ;; Try two different TLS/SSL libraries, but don't fail if none available. (or (ignore-errors (require 'tls)) (ignore-errors (require 'ssl))) (ignore-errors (require 'starttls)) (require 'srv) ;; This variable holds the connection, which is used for further ;; input/output to the server (defvar *jabber-connection* nil "the process that does the actual connection") (defgroup jabber-conn nil "Jabber Connection Settings" :group 'jabber) (defun jabber-have-starttls () "Return true if we can use STARTTLS." (and (featurep 'starttls) (or (and (bound-and-true-p starttls-gnutls-program) (executable-find starttls-gnutls-program)) (and (bound-and-true-p starttls-program) (executable-find starttls-program))))) (defconst jabber-default-connection-type (cond ;; Use STARTTLS if we can... ((jabber-have-starttls) 'starttls) ;; ...else default to unencrypted connection. (t 'network)) "Default connection type. See `jabber-connect-methods'.") (defcustom jabber-connection-ssl-program nil "Program used for SSL/TLS connections. nil means prefer gnutls but fall back to openssl. 'gnutls' means use gnutls (through `open-tls-stream'). 'openssl means use openssl (through `open-ssl-stream')." :type '(choice (const :tag "Prefer gnutls, fall back to openssl" nil) (const :tag "Use gnutls" gnutls) (const :tag "Use openssl" openssl)) :group 'jabber-conn) (defvar jabber-connect-methods '((network jabber-network-connect jabber-network-send) (starttls jabber-starttls-connect jabber-ssl-send) (ssl jabber-ssl-connect jabber-ssl-send) (virtual jabber-virtual-connect jabber-virtual-send)) "Alist of connection methods and functions. First item is the symbol naming the method. Second item is the connect function. Third item is the send function.") (defun jabber-get-connect-function (type) "Get the connect function associated with TYPE. TYPE is a symbol; see `jabber-connection-type'." (let ((entry (assq type jabber-connect-methods))) (nth 1 entry))) (defun jabber-get-send-function (type) "Get the send function associated with TYPE. TYPE is a symbol; see `jabber-connection-type'." (let ((entry (assq type jabber-connect-methods))) (nth 2 entry))) (defun jabber-srv-targets (server network-server port) "Find host and port to connect to. If NETWORK-SERVER and/or PORT are specified, use them. If we can't find SRV records, use standard defaults." ;; If the user has specified a host or a port, obey that. (if (or network-server port) (list (cons (or network-server server) (or port 5222))) (or (condition-case nil (srv-lookup (concat "_xmpp-client._tcp." server)) (error nil)) (list (cons server 5222))))) ;; Plain TCP/IP connection (defun jabber-network-connect (fsm server network-server port) "Connect to a Jabber server with a plain network connection. Send a message of the form (:connected CONNECTION) to FSM if connection succeeds. Send a message :connection-failed if connection fails." ;; XXX: asynchronous connection (let ((coding-system-for-read 'utf-8) (coding-system-for-write 'utf-8) (targets (jabber-srv-targets server network-server port))) (catch 'connected (dolist (target targets) (condition-case e (let ((process-buffer (generate-new-buffer jabber-process-buffer)) connection) (unwind-protect (setq connection (open-network-stream "jabber" process-buffer (car target) (cdr target))) (unless (or connection jabber-debug-keep-process-buffers) (kill-buffer process-buffer))) (when connection (fsm-send fsm (list :connected connection)) (throw 'connected connection))) (error (message "Couldn't connect to %s: %s" target (error-message-string e))))) (fsm-send fsm :connection-failed)))) (defun jabber-network-send (connection string) "Send a string via a plain TCP/IP connection to the Jabber Server." (process-send-string connection string)) ;; SSL connection, we use openssl's s_client function for encryption ;; of the link ;; TODO: make this configurable (defun jabber-ssl-connect (fsm server network-server port) "connect via OpenSSL or GnuTLS to a Jabber Server Send a message of the form (:connected CONNECTION) to FSM if connection succeeds. Send a message :connection-failed if connection fails." (let ((coding-system-for-read 'utf-8) (coding-system-for-write 'utf-8) (connect-function (cond ((and (memq jabber-connection-ssl-program '(nil gnutls)) (fboundp 'open-tls-stream)) 'open-tls-stream) ((and (memq jabber-connection-ssl-program '(nil openssl)) (fboundp 'open-ssl-stream)) 'open-ssl-stream) (t (error "Neither TLS nor SSL connect functions available"))))) (let ((process-buffer (generate-new-buffer jabber-process-buffer)) connection) (unwind-protect (setq connection (funcall connect-function "jabber" process-buffer (or network-server server) (or port 5223))) (unless (or connection jabber-debug-keep-process-buffers) (kill-buffer process-buffer))) (if connection (fsm-send fsm (list :connected connection)) (fsm-send fsm :connection-failed))))) (defun jabber-ssl-send (connection string) "Send a string via an SSL-encrypted connection to the Jabber Server." ;; It seems we need to send a linefeed afterwards. (process-send-string connection string) (process-send-string connection "\n")) (defun jabber-starttls-connect (fsm server network-server port) "Connect via GnuTLS to a Jabber Server. Send a message of the form (:connected CONNECTION) to FSM if connection succeeds. Send a message :connection-failed if connection fails." (let ((coding-system-for-read 'utf-8) (coding-system-for-write 'utf-8) (targets (jabber-srv-targets server network-server port))) (unless (fboundp 'starttls-open-stream) (error "starttls.el not available")) (catch 'connected (dolist (target targets) (condition-case e (let ((process-buffer (generate-new-buffer jabber-process-buffer)) connection) (unwind-protect (setq connection (starttls-open-stream "jabber" process-buffer (car target) (cdr target))) (unless (or connection jabber-debug-keep-process-buffers) (kill-buffer process-buffer))) (when connection (fsm-send fsm (list :connected connection)) (throw 'connected connection))) (error (message "Couldn't connect to %s: %s" target (error-message-string e)))) (fsm-send fsm :connection-failed))))) (defun jabber-starttls-initiate (fsm) "Initiate a starttls connection" (jabber-send-sexp fsm '(starttls ((xmlns . "urn:ietf:params:xml:ns:xmpp-tls"))))) (defun jabber-starttls-process-input (fsm xml-data) "Process result of starttls request. Return non-nil on success, nil on failure." (cond ((eq (car xml-data) 'proceed) (starttls-negotiate (plist-get (fsm-get-state-data fsm) :connection))) ((eq (car xml-data) 'failure) nil))) (defvar *jabber-virtual-server-function* nil "Function to use for sending stanzas on a virtual connection. The function should accept two arguments, the connection object and a string that the connection wants to send.") (defun jabber-virtual-connect (fsm server network-server port) "Connect to a virtual \"server\". Use `*jabber-virtual-server-function*' as send function." (unless (functionp *jabber-virtual-server-function*) (error "No virtual server function specified")) ;; We pass the fsm itself as "connection object", as that is what a ;; virtual server needs to send stanzas. (fsm-send fsm (list :connected fsm))) (defun jabber-virtual-send (connection string) (funcall *jabber-virtual-server-function* connection string)) (provide 'jabber-conn) ;; arch-tag: f95ec240-8cd3-11d9-9dbf-000a95c2fcd0 emacs-jabber-0.8.0/jabber-core.el0000644000175100017510000010537511250455045013466 00000000000000;; jabber-core.el - core functions ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; SSL-Connection Parts: ;; Copyright (C) 2005 - Georg Lehner - jorge@magma.com.ni ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'cl) (require 'jabber-util) (require 'jabber-logon) (require 'jabber-conn) (require 'fsm) (require 'jabber-sasl) (defvar jabber-connections nil "List of jabber-connection FSMs.") (defvar *jabber-roster* nil "the roster list") (defvar jabber-jid-obarray (make-vector 127 0) "obarray for keeping JIDs") (defvar *jabber-connected* nil "boolean - are we connected") (defvar *jabber-authenticated* nil "boolean - are we authenticated") (defvar *jabber-disconnecting* nil "boolean - are we in the process of disconnecting by free will") (defvar jabber-message-chain nil "Incoming messages are sent to these functions, in order.") (defvar jabber-iq-chain nil "Incoming infoqueries are sent to these functions, in order.") (defvar jabber-presence-chain nil "Incoming presence notifications are sent to these functions, in order.") (defvar jabber-choked-count 0 "Number of successive times that the process buffer has been nonempty.") (defvar jabber-choked-timer nil) (defgroup jabber-core nil "customize core functionality" :group 'jabber) (defcustom jabber-post-connect-hooks '(jabber-send-current-presence jabber-muc-autojoin jabber-whitespace-ping-start jabber-vcard-avatars-find-current) "*Hooks run after successful connection and authentication. The functions should accept one argument, the connection object." :type 'hook :options '(jabber-send-current-presence jabber-muc-autojoin jabber-whitespace-ping-start jabber-keepalive-start jabber-vcard-avatars-find-current jabber-autoaway-start) :group 'jabber-core) (defcustom jabber-pre-disconnect-hook nil "*Hooks run just before voluntary disconnection This might be due to failed authentication. Check `*jabber-authenticated*'." :type 'hook :group 'jabber-core) (defcustom jabber-lost-connection-hooks nil "*Hooks run after involuntary disconnection. The functions are called with one argument: the connection object." :type 'hook :group 'jabber-core) (defcustom jabber-post-disconnect-hook nil "*Hooks run after disconnection" :type 'hook :group 'jabber-core) (defcustom jabber-auto-reconnect nil "Reconnect automatically after losing connection? This will be of limited use unless you have the password library installed, and have configured it to cache your password indefinitely. See `password-cache' and `password-cache-expiry'." :type 'boolean :group 'jabber-core) (defcustom jabber-reconnect-delay 5 "Seconds to wait before reconnecting" :type 'integer :group 'jabber-core) (defcustom jabber-roster-buffer "*-jabber-roster-*" "The name of the roster buffer" :type 'string :group 'jabber-core) (defvar jabber-process-buffer " *-jabber-process-*" "The name of the process buffer") (defcustom jabber-use-sasl t "If non-nil, use SASL if possible. SASL will still not be used if the library for it is missing or if the server doesn't support it. Disabling this shouldn't be necessary, but it may solve certain problems." :type 'boolean :group 'jabber-core) (defsubst jabber-have-sasl-p () "Return non-nil if SASL functions are available." (featurep 'sasl)) (defvar jabber-account-history () "Keeps track of previously used jabber accounts") (defvar jabber-connection-type-history () "Keeps track of previously used connection types") ;; jabber-connect and jabber-connect-all should load jabber.el, not ;; just jabber-core.el, when autoloaded. ;;;###autoload (autoload 'jabber-connect-all "jabber" "Connect to all configured Jabber accounts.\nSee `jabber-account-list'.\nIf no accounts are configured (or ARG supplied), call `jabber-connect' interactively." t) (defun jabber-connect-all (&optional arg) "Connect to all configured Jabber accounts. See `jabber-account-list'. If no accounts are configured (or with prefix argument), call `jabber-connect' interactively. With many prefix arguments, one less is passed to `jabber-connect'." (interactive "P") (let ((accounts (remove-if (lambda (account) (cdr (assq :disabled (cdr account)))) jabber-account-list))) (if (or (null accounts) arg) (let ((current-prefix-arg (cond ;; A number of C-u's; remove one, so to speak. ((consp arg) (if (> (car arg) 4) (list (/ (car arg) 4)) nil)) ;; Otherwise, we just don't care. (t arg)))) (call-interactively 'jabber-connect)) ;; Only connect those accounts that are not yet connected. (let ((already-connected (mapcar #'jabber-connection-bare-jid jabber-connections)) (connected-one nil)) (dolist (account accounts) (unless (member (jabber-jid-user (car account)) already-connected) (let* ((jid (car account)) (alist (cdr account)) (password (cdr (assq :password alist))) (network-server (cdr (assq :network-server alist))) (port (cdr (assq :port alist))) (connection-type (cdr (assq :connection-type alist)))) (jabber-connect (jabber-jid-username jid) (jabber-jid-server jid) (jabber-jid-resource jid) nil password network-server port connection-type)))))))) ;;;###autoload (autoload 'jabber-connect "jabber" "Connect to the Jabber server and start a Jabber XML stream.\nWith prefix argument, register a new account.\nWith double prefix argument, specify more connection details." t) (defun jabber-connect (username server resource &optional registerp password network-server port connection-type) "Connect to the Jabber server and start a Jabber XML stream. With prefix argument, register a new account. With double prefix argument, specify more connection details." (interactive (let* ((jid (completing-read "Enter your JID: " jabber-account-list nil nil nil 'jabber-account-history)) (entry (assoc jid jabber-account-list)) (alist (cdr entry)) password network-server port connection-type registerp) (flet ((nonempty (s) (unless (zerop (length s)) s))) (when entry ;; If the user entered the JID of one of the preconfigured ;; accounts, use that data. (setq password (cdr (assq :password alist))) (setq network-server (cdr (assq :network-server alist))) (setq port (cdr (assq :port alist))) (setq connection-type (cdr (assq :connection-type alist)))) (when (equal current-prefix-arg '(16)) ;; Double prefix arg: ask about everything. ;; (except password, which is asked about later anyway) (setq password nil) (setq network-server (read-string (format "Network server: (default `%s') " network-server) nil nil network-server)) (when (zerop (length network-server)) (setq network-server nil)) (setq port (car (read-from-string (read-string (format "Port: (default `%s') " port) nil nil (if port (number-to-string port) "nil"))))) (setq connection-type (car (read-from-string (let ((default (symbol-name (or connection-type jabber-default-connection-type)))) (completing-read (format "Connection type: (default `%s') " default) (mapcar (lambda (type) (cons (symbol-name (car type)) nil)) jabber-connect-methods) nil t nil 'jabber-connection-type-history default))))) (setq registerp (yes-or-no-p "Register new account? "))) (when (equal current-prefix-arg '(4)) (setq registerp t)) (list (jabber-jid-username jid) (jabber-jid-server jid) (jabber-jid-resource jid) registerp password network-server port connection-type)))) (require 'jabber) (if (member (list username server) (mapcar (lambda (c) (let ((data (fsm-get-state-data c))) (list (plist-get data :username) (plist-get data :server)))) jabber-connections)) (message "Already connected to %s@%s" username server) (setq *jabber-authenticated* nil) ;;(jabber-clear-roster) (jabber-reset-choked) (push (start-jabber-connection username server resource registerp password network-server port connection-type) jabber-connections))) (define-state-machine jabber-connection :start ((username server resource registerp password network-server port connection-type) "Start a Jabber connection." (let* ((connection-type (or connection-type jabber-default-connection-type)) (send-function (jabber-get-send-function connection-type))) (list :connecting (list :send-function send-function :username username :server server :resource resource :password password :registerp registerp :connection-type connection-type :encrypted (eq connection-type 'ssl) :network-server network-server :port port))))) (define-enter-state jabber-connection nil (fsm state-data) ;; `nil' is the error state. ;; Close the network connection. (let ((connection (plist-get state-data :connection))) (when (processp connection) (let ((process-buffer (process-buffer connection))) (delete-process connection) (when (and (bufferp process-buffer) (not jabber-debug-keep-process-buffers)) (kill-buffer process-buffer))))) (setq state-data (plist-put state-data :connection nil)) ;; Remove lost connections from the roster buffer. (jabber-display-roster) (let ((expected (plist-get state-data :disconnection-expected)) (reason (plist-get state-data :disconnection-reason)) (ever-session-established (plist-get state-data :ever-session-established))) (unless expected (run-hook-with-args 'jabber-lost-connection-hooks fsm) (message "%s@%s/%s: connection lost: `%s'" (plist-get state-data :username) (plist-get state-data :server) (plist-get state-data :resource) reason)) (if (and jabber-auto-reconnect (not expected) ever-session-established) ;; Reconnect after a short delay? (list state-data jabber-reconnect-delay) ;; Else the connection is really dead. Remove it from the list ;; of connections. (setq jabber-connections (delq fsm jabber-connections)) (when jabber-mode-line-mode (jabber-mode-line-presence-update)) (jabber-display-roster) ;; And let the FSM sleep... (list state-data nil)))) (define-state jabber-connection nil (fsm state-data event callback) ;; In the `nil' state, the connection is dead. We wait for a ;; :timeout message, meaning to reconnect, or :do-disconnect, ;; meaning to cancel reconnection. (case event (:timeout (list :connecting state-data)) (:do-disconnect (setq jabber-connections (delq fsm jabber-connections)) (list nil state-data nil)))) (define-enter-state jabber-connection :connecting (fsm state-data) (let* ((connection-type (plist-get state-data :connection-type)) (connect-function (jabber-get-connect-function connection-type)) (server (plist-get state-data :server)) (network-server (plist-get state-data :network-server)) (port (plist-get state-data :port))) (funcall connect-function fsm server network-server port)) (list state-data nil)) (define-state jabber-connection :connecting (fsm state-data event callback) (case (or (car-safe event) event) (:connected (let ((connection (cadr event)) (registerp (plist-get state-data :registerp))) (setq state-data (plist-put state-data :connection connection)) (when (processp connection) ;; TLS connections leave data in the process buffer, which ;; the XML parser will choke on. (with-current-buffer (process-buffer connection) (erase-buffer)) (set-process-filter connection (fsm-make-filter fsm)) (set-process-sentinel connection (fsm-make-sentinel fsm))) (list :connected state-data))) (:connection-failed (message "Jabber connection failed") (list nil state-data)) (:do-disconnect ;; We don't have the connection object, so defer the disconnection. :defer))) (defsubst jabber-fsm-handle-sentinel (state-data event) "Handle sentinel event for jabber fsm." ;; We do the same thing for every state, so avoid code duplication. (let* ((string (car (cddr event))) (new-state-data ;; If we already know the reason (e.g. a stream error), don't ;; overwrite it. (if (plist-get state-data :disconnection-reason) state-data (plist-put state-data :disconnection-reason string)))) (list nil new-state-data))) (define-enter-state jabber-connection :connected (fsm state-data) (jabber-send-stream-header fsm) ;; XXX: Update to multiaccount? Remove? ;; (setq jabber-choked-timer ;; (run-with-timer 5 5 #'jabber-check-choked)) ;;XXX: why is this here? I'll try commenting it out... ;;(accept-process-output *jabber-connection*) ;; Next thing happening is the server sending its own start tag. (setq *jabber-connected* t) (list state-data nil)) (define-state jabber-connection :connected (fsm state-data event callback) (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :connected state-data))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stream-start (let ((session-id (cadr event)) (stream-version (car (cddr event)))) (setq state-data (plist-put state-data :session-id session-id)) ;; the stream feature is only sent if the initiating entity has ;; sent 1.0 in the stream header. if sasl is not supported then ;; we don't send 1.0 in the header and therefore we shouldn't wait ;; even if 1.0 is present in the receiving stream. (cond ;; Wait for stream features? ((and stream-version (>= (string-to-number stream-version) 1.0) jabber-use-sasl (jabber-have-sasl-p)) ;; Stay in same state... (list :connected state-data)) ;; Register account? ((plist-get state-data :registerp) ;; XXX: require encryption for registration? (list :register-account state-data)) ;; Legacy authentication? (t (list :legacy-auth state-data))))) (:stanza (let ((stanza (cadr event))) (cond ;; At this stage, we only expect a stream:features stanza. ((not (eq (jabber-xml-node-name stanza) 'stream:features)) (list nil (plist-put state-data :disconnection-reason (format "Unexpected stanza %s" stanza)))) ((and (jabber-xml-get-children stanza 'starttls) (eq (plist-get state-data :connection-type) 'starttls)) (list :starttls state-data)) ;; XXX: require encryption for registration? ((plist-get state-data :registerp) ;; We could check for the element in stream ;; features, but as a client we would only lose by doing ;; that. (list :register-account state-data)) (t (list :sasl-auth (plist-put state-data :stream-features stanza)))))) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (define-enter-state jabber-connection :starttls (fsm state-data) (jabber-starttls-initiate fsm) (list state-data nil)) (define-state jabber-connection :starttls (fsm state-data event callback) (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :starttls state-data))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stanza (if (jabber-starttls-process-input fsm (cadr event)) ;; Connection is encrypted. Send a stream tag again. (list :connected (plist-put state-data :encrypted t)) (message "STARTTLS negotiation failed") (list nil state-data))) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (define-enter-state jabber-connection :register-account (fsm state-data) (jabber-get-register fsm nil) (list state-data nil)) (define-state jabber-connection :register-account (fsm state-data event callback) ;; The connection will be closed in jabber-register (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :register-account state-data))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stanza (or (jabber-process-stream-error (cadr event) state-data) (progn (jabber-process-input fsm (cadr event)) (list :register-account state-data)))) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (define-enter-state jabber-connection :legacy-auth (fsm state-data) (jabber-get-auth fsm (plist-get state-data :server) (plist-get state-data :session-id)) (list state-data nil)) (define-state jabber-connection :legacy-auth (fsm state-data event callback) (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :legacy-auth state-data))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stanza (or (jabber-process-stream-error (cadr event) state-data) (progn (jabber-process-input fsm (cadr event)) (list :legacy-auth state-data)))) (:authentication-success (jabber-cache-password (jabber-connection-bare-jid fsm) (cdr event)) (list :session-established state-data)) (:authentication-failure (jabber-uncache-password (jabber-connection-bare-jid fsm)) ;; jabber-logon has already displayed a message (list nil (plist-put state-data :disconnection-expected t))) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (define-enter-state jabber-connection :sasl-auth (fsm state-data) (let ((new-state-data (plist-put state-data :sasl-data (jabber-sasl-start-auth fsm (plist-get state-data :stream-features))))) (list new-state-data nil))) (define-state jabber-connection :sasl-auth (fsm state-data event callback) (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :sasl-auth state-data))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stanza (let ((new-sasl-data (jabber-sasl-process-input fsm (cadr event) (plist-get state-data :sasl-data)))) (list :sasl-auth (plist-put state-data :sasl-data new-sasl-data)))) (:use-legacy-auth-instead (list :legacy-auth (plist-put state-data :sasl-data nil))) (:authentication-success (jabber-cache-password (jabber-connection-bare-jid fsm) (cdr event)) (list :bind (plist-put state-data :sasl-data nil))) (:authentication-failure (jabber-uncache-password (jabber-connection-bare-jid fsm)) ;; jabber-sasl has already displayed a message (list nil (plist-put state-data :disconnection-expected t))) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (define-enter-state jabber-connection :bind (fsm state-data) (jabber-send-stream-header fsm) (list state-data nil)) (define-state jabber-connection :bind (fsm state-data event callback) (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :bind state-data))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stream-start ;; we wait for stream features... (list :bind state-data)) (:stanza (let ((stanza (cadr event))) (cond ((eq (jabber-xml-node-name stanza) 'stream:features) (if (and (jabber-xml-get-children stanza 'bind) (jabber-xml-get-children stanza 'session)) (labels ((handle-bind (jc xml-data success) (fsm-send jc (list (if success :bind-success :bind-failure) xml-data)))) ;; So let's bind a resource. We can either pick a resource ourselves, ;; or have the server pick one for us. (let ((resource (plist-get state-data :resource))) (jabber-send-iq fsm nil "set" `(bind ((xmlns . "urn:ietf:params:xml:ns:xmpp-bind")) ,@(when resource `((resource () ,resource)))) #'handle-bind t #'handle-bind nil)) (list :bind state-data)) (message "Server doesn't permit resource binding and session establishing") (list nil state-data))) (t (or (jabber-process-stream-error (cadr event) state-data) (progn (jabber-process-input fsm (cadr event)) (list :bind state-data))))))) (:bind-success (let ((jid (jabber-xml-path (cadr event) '(bind jid "")))) ;; Maybe this isn't the JID we asked for. (plist-put state-data :username (jabber-jid-username jid)) (plist-put state-data :server (jabber-jid-server jid)) (plist-put state-data :resource (jabber-jid-resource jid))) ;; Been there, done that. Time to establish a session. (labels ((handle-session (jc xml-data success) (fsm-send jc (list (if success :session-success :session-failure) xml-data)))) (jabber-send-iq fsm nil "set" '(session ((xmlns . "urn:ietf:params:xml:ns:xmpp-session"))) #'handle-session t #'handle-session nil) (list :bind state-data))) (:session-success ;; We have a session (list :session-established state-data)) (:bind-failure (message "Resource binding failed: %s" (jabber-parse-error (jabber-iq-error (cadr event)))) (list nil state-data)) (:session-failure (message "Session establishing failed: %s" (jabber-parse-error (jabber-iq-error (cadr event)))) (list nil state-data)) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (define-enter-state jabber-connection :session-established (fsm state-data) (jabber-send-iq fsm nil "get" '(query ((xmlns . "jabber:iq:roster"))) #'jabber-process-roster 'initial #'jabber-report-success "Roster retrieval") (list (plist-put state-data :ever-session-established t) nil)) (defvar jabber-pending-presence-timeout 0.5 "Wait this long before doing presence packet batch processing.") (define-state jabber-connection :session-established (fsm state-data event callback) (case (or (car-safe event) event) (:filter (let ((process (cadr event)) (string (car (cddr event)))) (jabber-pre-filter process string fsm) (list :session-established state-data :keep))) (:sentinel (jabber-fsm-handle-sentinel state-data event)) (:stanza (or (jabber-process-stream-error (cadr event) state-data) (progn (jabber-process-input fsm (cadr event)) (list :session-established state-data :keep)))) (:roster-update ;; Batch up roster updates (let* ((jid-symbol-to-update (cdr event)) (pending-updates (plist-get state-data :roster-pending-updates))) ;; If there are pending updates, there is a timer running ;; already; just add the new symbol and wait. (if pending-updates (progn (unless (memq jid-symbol-to-update pending-updates) (nconc pending-updates (list jid-symbol-to-update))) (list :session-established state-data :keep)) ;; Otherwise, we need to create the list and start the timer. (setq state-data (plist-put state-data :roster-pending-updates (list jid-symbol-to-update))) (list :session-established state-data jabber-pending-presence-timeout)))) (:timeout ;; Update roster (let ((pending-updates (plist-get state-data :roster-pending-updates))) (setq state-data (plist-put state-data :roster-pending-updates nil)) (jabber-roster-update fsm nil pending-updates nil) (list :session-established state-data))) (:send-if-connected ;; This is the only state in which we respond to such messages. ;; This is to make sure we don't send anything inappropriate ;; during authentication etc. (jabber-send-sexp fsm (cdr event)) (list :session-established state-data :keep)) (:do-disconnect (jabber-send-string fsm "") (list nil (plist-put state-data :disconnection-expected t))))) (defun jabber-disconnect (&optional arg) "Disconnect from all Jabber servers. If ARG supplied, disconnect one account." (interactive "P") (if arg (jabber-disconnect-one (jabber-read-account)) (unless *jabber-disconnecting* ; avoid reentry (let ((*jabber-disconnecting* t)) (run-hooks 'jabber-pre-disconnect-hook) (dolist (c jabber-connections) (jabber-disconnect-one c t)) (setq jabber-connections nil) (jabber-disconnected) (when (interactive-p) (message "Disconnected from Jabber server(s)")))))) (defun jabber-disconnect-one (jc &optional dont-redisplay) "Disconnect from one Jabber server. If DONT-REDISPLAY is non-nil, don't update roster buffer." (interactive (list (jabber-read-account))) (fsm-send-sync jc :do-disconnect) (when (interactive-p) (message "Disconnected from %s" (jabber-connection-jid jc))) (unless dont-redisplay (jabber-display-roster))) (defun jabber-disconnected () "Re-initialise jabber package variables. Call this function after disconnection." (when jabber-choked-timer (jabber-cancel-timer jabber-choked-timer) (setq jabber-choked-timer nil)) (when (get-buffer jabber-roster-buffer) (with-current-buffer (get-buffer jabber-roster-buffer) (let ((inhibit-read-only t)) (erase-buffer)))) (setq *jabber-connection* nil) (jabber-clear-roster) (setq *jabber-authenticated* nil) (setq *jabber-connected* nil) (setq *jabber-active-groupchats* nil) (run-hooks 'jabber-post-disconnect-hook)) (defun jabber-log-xml (fsm direction data) "Print DATA to XML log. If `jabber-debug-log-xml' is nil, do nothing. FSM is the connection that is sending/receiving. DIRECTION is a string, either \"sending\" or \"receive\". DATA is any sexp." (when jabber-debug-log-xml (with-current-buffer (get-buffer-create (format "*-jabber-xml-log-%s-*" (jabber-connection-bare-jid fsm))) (save-excursion (goto-char (point-max)) (insert (format "%s %S\n\n" direction data)))))) (defun jabber-pre-filter (process string fsm) (with-current-buffer (process-buffer process) ;; Append new data (goto-char (point-max)) (insert string) (unless (boundp 'jabber-filtering) (let (jabber-filtering) (jabber-filter process fsm))))) (defun jabber-filter (process fsm) "the filter function for the jabber process" (with-current-buffer (process-buffer process) ;; Start from the beginning (goto-char (point-min)) (let (xml-data) (loop do ;; Skip whitespace (unless (zerop (skip-chars-forward " \t\r\n")) (delete-region (point-min) (point))) ;; Skip processing directive (when (looking-at "<\\?xml[^?]*\\?>") (delete-region (match-beginning 0) (match-end 0))) ;; Stream end? (when (looking-at "") (return (fsm-send fsm :stream-end))) ;; Stream header? (when (looking-at "]*>") (let ((stream-header (match-string 0)) (ending-at (match-end 0)) session-id stream-version) ;; These regexps extract attribute values from the stream ;; header, taking into account that the quotes may be either ;; single or double quotes. (setq session-id (and (or (string-match "id='\\([^']+\\)'" stream-header) (string-match "id=\"\\([^\"]+\\)\"" stream-header)) (jabber-unescape-xml (match-string 1 stream-header)))) (setq stream-version (and (or (string-match "version='\\([0-9.]+\\)'" stream-header) (string-match "version=\"\\([0-9.]+\\)\"" stream-header)) (match-string 1 stream-header))) (jabber-log-xml fsm "receive" stream-header) ;; If the server is XMPP compliant, i.e. there is a version attribute ;; and it's >= 1.0, there will be a stream:features tag shortly, ;; so just wait for that. (fsm-send fsm (list :stream-start session-id stream-version)) (delete-region (point-min) ending-at))) ;; Normal tag ;; XXX: do these checks make sense? If so, reinstate them. ;;(if (active-minibuffer-window) ;; (run-with-idle-timer 0.01 nil #'jabber-filter process string) ;; This check is needed for xml.el of Emacs 21, as it chokes on ;; empty attribute values. (save-excursion (while (search-forward-regexp " \\w+=''" nil t) (replace-match ""))) (setq xml-data (and (catch 'unfinished (jabber-xml-skip-tag-forward) (> (point) (point-min))) (xml-parse-region (point-min) (point)))) (if xml-data (jabber-reset-choked)) while xml-data do ;; If there's a problem with writing the XML log, ;; make sure the stanza is delivered, at least. (condition-case e (jabber-log-xml fsm "receive" (car xml-data)) (error (ding) (message "Couldn't write XML log: %s" (error-message-string e)) (sit-for 2))) (delete-region (point-min) (point)) (fsm-send fsm (list :stanza (car xml-data))) ;; XXX: move this logic elsewhere ;; We explicitly don't catch errors in jabber-process-input, ;; to facilitate debugging. ;; (jabber-process-input (car xml-data)) )))) (defun jabber-reset-choked () (setq jabber-choked-count 0)) (defun jabber-check-choked () ;; "Choked" means that data is sitting in the process buffer ;; without being parsed, despite several attempts. (if (zerop (buffer-size (process-buffer *jabber-connection*))) (jabber-reset-choked) (incf jabber-choked-count) (if (and (> jabber-choked-count 3) ;; Now we're definitely choked. Take action. ;; But ask user first. (yes-or-no-p "jabber.el is severely confused. Bail out? ")) (run-with-idle-timer 0.1 nil 'jabber-choked-bail-out) (jabber-reset-choked)))) (defun jabber-choked-bail-out () ;; So here we are. Something in the process buffer prevents us ;; from continuing normally. Let's die honorably by providing ;; bug report material. (with-current-buffer (generate-new-buffer "*jabber-bug*") (insert "jabber.el couldn't cope with the data received from the server. This should never happen, but apparently it did. The information below will be helpful in tracking down and fixing the bug. You may want to edit out any sensitive information. Please go to http://sourceforge.net/tracker/?group_id=88346&atid=586350 and submit a bug report, including the information below. ") (goto-address) (emacs-version t) (insert "\n\nThe following couldn't be parsed:\n") (insert-buffer-substring (process-buffer *jabber-connection*)) (switch-to-buffer (current-buffer))) (jabber-disconnect)) (defun jabber-process-input (jc xml-data) "process an incoming parsed tag" (let* ((tag (jabber-xml-node-name xml-data)) (functions (eval (cdr (assq tag '((iq . jabber-iq-chain) (presence . jabber-presence-chain) (message . jabber-message-chain))))))) (dolist (f functions) (condition-case e (funcall f jc xml-data) ((debug error) (fsm-debug-output "Error %S while processing %S with function %s" e xml-data f)))))) (defun jabber-process-stream-error (xml-data state-data) "Process an incoming stream error. Return nil if XML-DATA is not a stream:error stanza. Return an fsm result list if it is." (when (eq (jabber-xml-node-name xml-data) 'stream:error) (let ((condition (jabber-stream-error-condition xml-data)) (text (jabber-parse-stream-error xml-data))) (setq state-data (plist-put state-data :disconnection-reason (format "Stream error: %s" text))) ;; Special case: when the error is `conflict', we have been ;; forcibly disconnected by the same user. Don't reconnect ;; automatically. (when (eq condition 'conflict) (setq state-data (plist-put state-data :disconnection-expected t))) (list nil state-data)))) ;; XXX: This function should probably die. The roster is stored ;; inside the connection plists, and the obarray shouldn't be so big ;; that we need to clean it. (defun jabber-clear-roster () "Clean up the roster." ;; This is made complicated by the fact that the JIDs are symbols with properties. (mapatoms #'(lambda (x) (unintern x jabber-jid-obarray)) jabber-jid-obarray) (setq *jabber-roster* nil)) (defun jabber-send-sexp (jc sexp) "Send the xml corresponding to SEXP to connection JC." (condition-case e (jabber-log-xml jc "sending" sexp) (error (ding) (message "Couldn't write XML log: %s" (error-message-string e)) (sit-for 2))) (jabber-send-string jc (jabber-sexp2xml sexp))) (defun jabber-send-sexp-if-connected (jc sexp) "Send the stanza SEXP only if JC has established a session." (fsm-send-sync jc (cons :send-if-connected sexp))) (defun jabber-send-stream-header (jc) "Send stream header to connection JC." (let ((stream-header (concat " "))) (jabber-log-xml jc "sending" stream-header) (jabber-send-string jc stream-header))) (defun jabber-send-string (jc string) "Send STRING to the connection JC." (let* ((state-data (fsm-get-state-data jc)) (connection (plist-get state-data :connection)) (send-function (plist-get state-data :send-function))) (unless connection (error "%s has no connection" (jabber-connection-jid jc))) (funcall send-function connection string))) (provide 'jabber-core) ;;; arch-tag: 9d273ce6-c45a-447b-abf3-21d3ce73a51a emacs-jabber-0.8.0/jabber-disco.el0000644000175100017510000001724311133727374013642 00000000000000;; jabber-disco.el - service discovery functions ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; All the client part should be seriously rewritten, or at least ;;; reconsidered. I'm imagining a separation between backend and ;;; frontend, so that various functions can perform disco queries for ;;; their own purposes, and maybe some caching with that. (require 'jabber-iq) (require 'jabber-xml) (require 'jabber-menu) ;; Advertise your features here. Add the namespace to this list. (defvar jabber-advertised-features (list "http://jabber.org/protocol/disco#info") "Features advertised on service discovery requests") (defvar jabber-disco-items-nodes (list (list "" nil nil)) "Alist of node names and information about returning disco item data. Key is node name as a string, or \"\" for no node specified. Value is a list of two items. First item is data to return. If it is a function, that function is called and its return value is used; if it is a list, that list is used. The list should be the XML data to be returned inside the element, like this: \((item ((name . \"Name of first item\") (jid . \"first.item\") (node . \"node\")))) Second item is access control function. That function is passed the JID, and returns non-nil if access is granted. If the second item is nil, access is always granted.") (defvar jabber-disco-info-nodes (list (list "" #'jabber-disco-return-client-info nil)) "Alist of node names and information returning disco info data. Key is node name as a string, or \"\" for no node specified. Value is a list of two items. First item is data to return. If it is a function, that function is called and its return value is used; if it is a list, that list is used. The list should be the XML data to be returned inside the element, like this: \((identity ((category . \"client\") (type . \"pc\") (name . \"Jabber client\"))) (feature ((var . \"some-feature\")))) Second item is access control function. That function is passed the JID, and returns non-nil if access is granted. If the second item is nil, access is always granted.") (defun jabber-process-disco-info (jc xml-data) "Handle results from info disco requests." (let ((beginning (point))) (dolist (x (jabber-xml-node-children (jabber-iq-query xml-data))) (cond ((eq (jabber-xml-node-name x) 'identity) (let ((name (jabber-xml-get-attribute x 'name)) (category (jabber-xml-get-attribute x 'category)) (type (jabber-xml-get-attribute x 'type))) (insert (jabber-propertize (if name name "Unnamed") 'face 'jabber-title-medium) "\n\nCategory:\t" category "\n") (if type (insert "Type:\t\t" type "\n")) (insert "\n"))) ((eq (jabber-xml-node-name x) 'feature) (let ((var (jabber-xml-get-attribute x 'var))) (insert "Feature:\t" var "\n"))))) (put-text-property beginning (point) 'jabber-jid (jabber-xml-get-attribute xml-data 'from)) (put-text-property beginning (point) 'jabber-account jc))) (defun jabber-process-disco-items (jc xml-data) "Handle results from items disco requests." (let ((items (jabber-xml-get-children (jabber-iq-query xml-data) 'item))) (if items (dolist (item items) (let ((jid (jabber-xml-get-attribute item 'jid)) (name (jabber-xml-get-attribute item 'name)) (node (jabber-xml-get-attribute item 'node))) (insert (jabber-propertize (concat (jabber-propertize (concat jid "\n" (if node (format "Node: %s\n" node))) 'face 'jabber-title-medium) name "\n\n") 'jabber-jid jid 'jabber-account jc 'jabber-node node)))) (insert "No items found.\n")))) (add-to-list 'jabber-iq-get-xmlns-alist (cons "http://jabber.org/protocol/disco#info" 'jabber-return-disco-info)) (add-to-list 'jabber-iq-get-xmlns-alist (cons "http://jabber.org/protocol/disco#items" 'jabber-return-disco-info)) (defun jabber-return-disco-info (jc xml-data) "Respond to a service discovery request. See JEP-0030." (let* ((to (jabber-xml-get-attribute xml-data 'from)) (id (jabber-xml-get-attribute xml-data 'id)) (xmlns (jabber-iq-xmlns xml-data)) (which-alist (eval (cdr (assoc xmlns (list (cons "http://jabber.org/protocol/disco#info" 'jabber-disco-info-nodes) (cons "http://jabber.org/protocol/disco#items" 'jabber-disco-items-nodes)))))) (node (or (jabber-xml-get-attribute (jabber-iq-query xml-data) 'node) "")) (return-list (cdr (assoc node which-alist))) (func (nth 0 return-list)) (access-control (nth 1 return-list))) (if return-list (if (and (functionp access-control) (not (funcall access-control jc to))) (jabber-signal-error "cancel" 'not-allowed) ;; Access control passed (let ((result (if (functionp func) (funcall func jc xml-data) func))) (jabber-send-iq jc to "result" `(query ((xmlns . ,xmlns) ,@(when node (list (cons 'node node)))) ,@result) nil nil nil nil id))) ;; No such node (jabber-signal-error "cancel" 'item-not-found)))) (defun jabber-disco-return-client-info (jc xml-data) `( ;; If running under a window system, this is ;; a GUI client. If not, it is a console client. (identity ((category . "client") (name . "Emacs Jabber client") (type . ,(if (memq window-system '(x w32 mac)) "pc" "console")))) ,@(mapcar #'(lambda (featurename) `(feature ((var . ,featurename)))) jabber-advertised-features))) (add-to-list 'jabber-jid-info-menu (cons "Send items disco query" 'jabber-get-disco-items)) (defun jabber-get-disco-items (jc to &optional node) "Send a service discovery request for items" (interactive (list (jabber-read-account) (jabber-read-jid-completing "Send items disco request to: ") (jabber-read-node "Node (or leave empty): "))) (jabber-send-iq jc to "get" (list 'query (append (list (cons 'xmlns "http://jabber.org/protocol/disco#items")) (if (> (length node) 0) (list (cons 'node node))))) #'jabber-process-data #'jabber-process-disco-items #'jabber-process-data "Item discovery failed")) (add-to-list 'jabber-jid-info-menu (cons "Send info disco query" 'jabber-get-disco-info)) (defun jabber-get-disco-info (jc to &optional node) "Send a service discovery request for info" (interactive (list (jabber-read-account) (jabber-read-jid-completing "Send info disco request to: ") (jabber-read-node "Node (or leave empty): "))) (jabber-send-iq jc to "get" (list 'query (append (list (cons 'xmlns "http://jabber.org/protocol/disco#info")) (if (> (length node) 0) (list (cons 'node node))))) #'jabber-process-data #'jabber-process-disco-info #'jabber-process-data "Info discovery failed")) (provide 'jabber-disco) ;;; arch-tag: 71f5c76f-2956-4ed2-b871-9f5fe198092d emacs-jabber-0.8.0/jabber-events.el0000644000175100017510000002153711133727374014046 00000000000000;;; jabber-events.el --- Message events (JEP-0022) implementation ;; Copyright (C) 2005, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. (require 'jabber-autoloads) (require 'cl) (defgroup jabber-events nil "Message events and notifications." :group 'jabber) ;;; INCOMING ;;; Code for requesting event notifications from others and handling ;;; them. (defcustom jabber-events-request-these '(offline delivered displayed composing) "Request these kinds of event notifications from others." :type '(set (const :tag "Delivered to offline storage" offline) (const :tag "Delivered to user's client" delivered) (const :tag "Displayed to user" displayed) (const :tag "User is typing a reply" composing)) :group 'jabber-events) (defvar jabber-events-composing-p nil "Is the other person composing a message?") (make-variable-buffer-local 'jabber-events-composing-p) (defvar jabber-events-arrived nil "In what way has the message reached the recipient? Possible values are nil (no information available), offline \(queued for delivery when recipient is online), delivered \(message has reached the client) and displayed (user is probably reading the message).") (make-variable-buffer-local 'jabber-events-arrived) (defvar jabber-events-message "" "Human-readable presentation of event information") (make-variable-buffer-local 'jabber-events-message) (defun jabber-events-update-message () (setq jabber-events-message (concat (cdr (assq jabber-events-arrived '((offline . "In offline storage") (delivered . "Delivered") (displayed . "Displayed")))) (when jabber-events-composing-p " (typing a message)")))) (add-hook 'jabber-chat-send-hooks 'jabber-events-when-sending) (defun jabber-events-when-sending (text id) (setq jabber-events-arrived nil) (jabber-events-update-message) `((x ((xmlns . "jabber:x:event")) ,@(mapcar #'list jabber-events-request-these)))) ;;; OUTGOING ;;; Code for handling requests for event notifications and providing ;;; them, modulo user preferences. (defcustom jabber-events-confirm-delivered t "Send delivery confirmation if requested?" :group 'jabber-events :type 'boolean) (defcustom jabber-events-confirm-displayed t "Send display confirmation if requested?" :group 'jabber-events :type 'boolean) (defcustom jabber-events-confirm-composing t "Send notifications about typing a reply?" :group 'jabber-events :type 'boolean) (defvar jabber-events-requested () "List of events requested") (make-variable-buffer-local 'jabber-events-requested) (defvar jabber-events-last-id nil "Id of last message received, or nil if none.") (make-variable-buffer-local 'jabber-events-last-id) (defvar jabber-events-delivery-confirmed nil "Has delivery confirmation been sent?") (make-variable-buffer-local 'jabber-events-delivery-confirmed) (defvar jabber-events-display-confirmed nil "Has display confirmation been sent?") (make-variable-buffer-local 'jabber-events-display-confirmed) (defvar jabber-events-composing-sent nil "Has composing notification been sent? It can be sent and cancelled several times.") (add-hook 'window-configuration-change-hook 'jabber-events-confirm-display) (defun jabber-events-confirm-display () "Send display confirmation if appropriate. That is, if user allows it, if the other user requested it, and it hasn't been sent before." (walk-windows #'jabber-events-confirm-display-in-window)) (defun jabber-events-confirm-display-in-window (window) (with-current-buffer (window-buffer window) (when (and jabber-events-confirm-displayed (not jabber-events-display-confirmed) (memq 'displayed jabber-events-requested) ;; XXX: if jabber-events-requested is non-nil, how can ;; jabber-chatting-with be nil? See ;; http://sourceforge.net/tracker/index.php?func=detail&aid=1872560&group_id=88346&atid=586350 jabber-chatting-with ;; don't send to bare jids (jabber-jid-resource jabber-chatting-with)) (jabber-send-sexp jabber-buffer-connection `(message ((to . ,jabber-chatting-with)) (x ((xmlns . "jabber:x:event")) (displayed) (id () ,jabber-events-last-id)))) (setq jabber-events-display-confirmed t)))) (defun jabber-events-after-change () (let ((composing-now (not (= (point-max) jabber-point-insert)))) (when (and jabber-events-confirm-composing jabber-chatting-with (not (eq composing-now jabber-events-composing-sent))) (jabber-send-sexp jabber-buffer-connection `(message ((to . ,jabber-chatting-with)) (x ((xmlns . "jabber:x:event")) ,@(if composing-now '((composing)) nil) (id () ,jabber-events-last-id)))) (setq jabber-events-composing-sent composing-now)))) ;;; COMMON ;; Add function last in chain, so a chat buffer is already created. (add-to-list 'jabber-message-chain 'jabber-handle-incoming-message-events t) (defun jabber-handle-incoming-message-events (jc xml-data) (when (and (not (jabber-muc-message-p xml-data)) (get-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from)))) (with-current-buffer (jabber-chat-get-buffer (jabber-xml-get-attribute xml-data 'from)) (let ((x (find "jabber:x:event" (jabber-xml-get-children xml-data 'x) :key #'(lambda (x) (jabber-xml-get-attribute x 'xmlns)) :test #'string=))) (cond ;; If we get an error message, we shouldn't report any ;; events, as the requests are mirrored from us. ((string= (jabber-xml-get-attribute xml-data 'type) "error") (remove-hook 'post-command-hook 'jabber-events-after-change t) (setq jabber-events-requested nil)) ;; If there's a body, it's not an incoming message event. ((jabber-xml-get-children xml-data 'body) ;; User is done composing, obviously. (setq jabber-events-composing-p nil) (jabber-events-update-message) ;; Reset variables (setq jabber-events-display-confirmed nil) (setq jabber-events-delivery-confirmed nil) ;; User requests message events (setq jabber-events-requested ;; There might be empty strings in the XML data, ;; which car chokes on. Having nil values in ;; the list won't hurt, therefore car-safe. (mapcar #'car-safe (jabber-xml-node-children x))) (setq jabber-events-last-id (jabber-xml-get-attribute xml-data 'id)) ;; Send notifications we already know about (flet ((send-notification (type) (jabber-send-sexp jc `(message ((to . ,(jabber-xml-get-attribute xml-data 'from))) (x ((xmlns . "jabber:x:event")) (,type) (id () ,jabber-events-last-id)))))) ;; Send delivery confirmation if appropriate (when (and jabber-events-confirm-delivered (memq 'delivered jabber-events-requested)) (send-notification 'delivered) (setq jabber-events-delivery-confirmed t)) ;; Send display confirmation if appropriate (when (and jabber-events-confirm-displayed (get-buffer-window (current-buffer) 'visible) (memq 'displayed jabber-events-requested)) (send-notification 'displayed) (setq jabber-events-display-confirmed t)) ;; Set up hooks for composition notification (when (and jabber-events-confirm-composing (memq 'composing jabber-events-requested)) (add-hook 'post-command-hook 'jabber-events-after-change nil t)))) (t ;; So it has no body. If it's a message event, ;; the node should be the only child of the ;; message, and it should contain an node. ;; We check the latter. (when (and x (jabber-xml-get-children x 'id)) ;; Currently we don't care about the node. ;; There's only one node except for the id. (unless (dolist (possible-node '(offline delivered displayed)) (when (jabber-xml-get-children x possible-node) (setq jabber-events-arrived possible-node) (jabber-events-update-message) (return t))) ;; Or maybe even zero, which is a negative composing node. (setq jabber-events-composing-p (not (null (jabber-xml-get-children x 'composing)))) (jabber-events-update-message))))))))) (provide 'jabber-events) ;; arch-tag: 7b6e61fe-a9b3-11d9-afca-000a95c2fcd0 emacs-jabber-0.8.0/jabber-export.el0000644000175100017510000002060211133727374014053 00000000000000;;; jabber-export.el --- export Jabber roster to file ;; Copyright (C) 2005, 2007 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. (require 'cl) (defvar jabber-export-roster-widget nil) (defvar jabber-import-subscription-p-widget nil) ;;;###autoload (defun jabber-export-roster (jc) "Export roster for connection JC." (interactive (list (jabber-read-account))) (let ((state-data (fsm-get-state-data jc))) (jabber-export-roster-do-it (jabber-roster-to-sexp (plist-get state-data :roster))))) (defun jabber-export-roster-do-it (roster) "Create buffer from which ROSTER can be exported to a file." (interactive) (with-current-buffer (get-buffer-create "Export roster") (jabber-init-widget-buffer nil) (widget-insert (jabber-propertize "Export roster\n" 'face 'jabber-title-large)) (widget-insert "You are about to save your roster to a file. Here you can edit it before saving. Changes done here will not affect your actual roster. ") (widget-create 'push-button :notify #'jabber-export-save "Save to file") (widget-insert " ") (widget-create 'push-button :notify #'jabber-export-remove-regexp "Remove by regexp") (widget-insert "\n\n") (make-local-variable 'jabber-export-roster-widget) (jabber-export-display roster) (widget-setup) (widget-minor-mode 1) (goto-char (point-min)) (switch-to-buffer (current-buffer)))) ;;;###autoload (defun jabber-import-roster (jc file) "Create buffer for roster import for connection JC from FILE." (interactive (list (jabber-read-account) (read-file-name "Import roster from file: "))) (let ((roster (with-temp-buffer (let ((coding-system-for-read 'utf-8)) (jabber-roster-xml-to-sexp (car (xml-parse-file file))))))) (with-current-buffer (get-buffer-create "Import roster") (setq jabber-buffer-connection jc) (jabber-init-widget-buffer nil) (widget-insert (jabber-propertize "Import roster\n" 'face 'jabber-title-large)) (widget-insert "You are about to import the contacts below to your roster. ") (make-local-variable 'jabber-import-subscription-p-widget) (setq jabber-import-subscription-p-widget (widget-create 'checkbox)) (widget-insert " Adjust subscriptions\n") (widget-create 'push-button :notify #'jabber-import-doit "Import to roster") (widget-insert " ") (widget-create 'push-button :notify #'jabber-export-remove-regexp "Remove by regexp") (widget-insert "\n\n") (make-local-variable 'jabber-export-roster-widget) (jabber-export-display roster) (widget-setup) (widget-minor-mode 1) (goto-char (point-min)) (switch-to-buffer (current-buffer))))) (defun jabber-export-remove-regexp (&rest ignore) (let* ((value (widget-value jabber-export-roster-widget)) (length-before (length value)) (regexp (read-string "Remove JIDs matching regexp: "))) (setq value (delete-if #'(lambda (a) (string-match regexp (nth 0 a))) value)) (widget-value-set jabber-export-roster-widget value) (widget-setup) (message "%d items removed" (- length-before (length value))))) (defun jabber-export-save (&rest ignore) "Export roster to file." (let ((items (mapcar #'jabber-roster-sexp-to-xml (widget-value jabber-export-roster-widget))) (coding-system-for-write 'utf-8)) (with-temp-file (read-file-name "Export roster to file: ") (insert "\n") (dolist (item items) (insert (jabber-sexp2xml item) "\n")) (insert "\n")) (message "Roster saved"))) (defun jabber-import-doit (&rest ignore) "Import roster being edited in widget." (let* ((state-data (fsm-get-state-data jabber-buffer-connection)) (jabber-roster (plist-get state-data :roster)) roster-delta) (dolist (n (widget-value jabber-export-roster-widget)) (let* ((jid (nth 0 n)) (name (and (not (zerop (length (nth 1 n)))) (nth 1 n))) (subscription (nth 2 n)) (groups (nth 3 n)) (jid-symbol (jabber-jid-symbol jid)) (in-roster-p (memq jid-symbol jabber-roster)) (jid-name (and in-roster-p (get jid-symbol 'name))) (jid-subscription (and in-roster-p (get jid-symbol 'subscription))) (jid-groups (and in-roster-p (get jid-symbol 'groups)))) ;; Do we need to change the roster? (when (or ;; If the contact is not in the roster already, (not in-roster-p) ;; or if the import introduces a name, (and name (not jid-name)) ;; or changes a name, (and name jid-name (not (string= name jid-name))) ;; or introduces new groups. (set-difference groups jid-groups :test #'string=)) (push (jabber-roster-sexp-to-xml (list jid (or name jid-name) nil (union groups jid-groups :test #'string=)) t) roster-delta)) ;; And adujst subscription. (when (widget-value jabber-import-subscription-p-widget) (let ((want-to (member subscription '("to" "both"))) (want-from (member subscription '("from" "both"))) (have-to (member jid-subscription '("to" "both"))) (have-from (member jid-subscription '("from" "both")))) (flet ((request-subscription (type) (jabber-send-sexp jabber-buffer-connection `(presence ((to . ,jid) (type . ,type)))))) (cond ((and want-to (not have-to)) (request-subscription "subscribe")) ((and have-to (not want-to)) (request-subscription "unsubscribe"))) (cond ((and want-from (not have-from)) ;; not much to do here ) ((and have-from (not want-from)) (request-subscription "unsubscribed")))))))) (when roster-delta (jabber-send-iq jabber-buffer-connection nil "set" `(query ((xmlns . "jabber:iq:roster")) ,@roster-delta) #'jabber-report-success "Roster import" #'jabber-report-success "Roster import")))) (defun jabber-roster-to-sexp (roster) "Convert ROSTER to simpler sexp format. Return a list, where each item is a vector: \[jid name subscription groups] where groups is a list of strings." (mapcar #'(lambda (n) (list (symbol-name n) (or (get n 'name) "") (get n 'subscription) (get n 'groups))) roster)) (defun jabber-roster-sexp-to-xml (sexp &optional omit-subscription) "Convert SEXP to XML format. Return an XML node." `(item ((jid . ,(nth 0 sexp)) ,@(let ((name (nth 1 sexp))) (unless (zerop (length name)) `((name . ,name)))) ,@(unless omit-subscription `((subscription . ,(nth 2 sexp))))) ,@(mapcar #'(lambda (g) (list 'group nil g)) (nth 3 sexp)))) (defun jabber-roster-xml-to-sexp (xml-data) "Convert XML-DATA to simpler sexp format. XML-DATA is an node with a child. See `jabber-roster-to-sexp' for description of output format." (assert (eq (jabber-xml-node-name xml-data) 'iq)) (let ((query (car (jabber-xml-get-children xml-data 'query)))) (assert query) (mapcar #'(lambda (n) (list (jabber-xml-get-attribute n 'jid) (or (jabber-xml-get-attribute n 'name) "") (jabber-xml-get-attribute n 'subscription) (mapcar #'(lambda (g) (car (jabber-xml-node-children g))) (jabber-xml-get-children n 'group)))) (jabber-xml-get-children query 'item)))) (defun jabber-export-display (roster) (setq jabber-export-roster-widget (widget-create '(repeat :tag "Roster" (list :format "%v" (string :tag "JID") (string :tag "Name") (choice :tag "Subscription" (const "none") (const "both") (const "to") (const "from")) (repeat :tag "Groups" (string :tag "Group")))) :value roster))) (provide 'jabber-export) ;;; arch-tag: 9c6b94a9-290a-4c0f-9286-72bd9c1fb8a3 emacs-jabber-0.8.0/jabber-feature-neg.el0000644000175100017510000001063311133727374014737 00000000000000;; jabber-feature-neg.el - Feature Negotiation by JEP-0020 ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; Copyright (C) 2003, 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-disco) (require 'cl) (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/feature-neg") (defun jabber-fn-parse (xml-data type) "Parse a Feature Negotiation request, return alist representation. XML-DATA should have one child element, , in the jabber:x:data namespace. TYPE is either 'request or 'response. Returned alist has field name as key, and value is a list of offered alternatives." (let ((x (car (jabber-xml-get-children xml-data 'x)))) (unless (and x (string= (jabber-xml-get-attribute x 'xmlns) "jabber:x:data")) (jabber-signal-error "modify" 'bad-request "Malformed Feature Negotiation")) (let (alist (fields (jabber-xml-get-children x 'field))) (dolist (field fields) (let ((var (jabber-xml-get-attribute field 'var)) (value (car (jabber-xml-get-children field 'value))) (options (jabber-xml-get-children field 'option))) (setq alist (cons (cons var (cond ((eq type 'request) (mapcar #'(lambda (option) (car (jabber-xml-node-children (car (jabber-xml-get-children option 'value))))) options)) ((eq type 'response) (jabber-xml-node-children value)) (t (error "Incorrect Feature Negotiation type: %s" type)))) alist)))) ;; return alist alist))) (defun jabber-fn-encode (alist type) "Transform a feature alist into an node int the jabber:x:data namespace. Note that this is not the reverse of `jabber-fn-parse'. TYPE is either 'request or 'response." (let ((requestp (eq type 'request))) `(x ((xmlns . "jabber:x:data") (type . ,(if requestp "form" "submit"))) ,@(mapcar #'(lambda (field) `(field ((type . "list-single") (var . ,(car field))) ,@(if requestp (mapcar #'(lambda (option) `(option nil (value nil ,option))) (cdr field)) (list `(value nil ,(cadr field)))))) alist)))) (defun jabber-fn-intersection (mine theirs) "Find values acceptable to both parties. MINE and THEIRS are alists, as returned by `jabber-fn-parse'. An alist is returned, where the keys are the negotiated variables, and the values are lists containing the preferred option. If negotiation is impossible, an error is signalled. The errors are as specified in JEP-0020, and not necessarily the ones of higher-level protocols." (let ((vars (mapcar #'car mine)) (their-vars (mapcar #'car theirs))) ;; are the same variables being negotiated? (sort vars 'string-lessp) (sort their-vars 'string-lessp) (let ((mine-but-not-theirs (set-difference vars their-vars :test 'string=)) (theirs-but-not-mine (set-difference their-vars vars :test 'string=))) (when mine-but-not-theirs (jabber-signal-error "modify" 'not-acceptable (car mine-but-not-theirs))) (when theirs-but-not-mine (jabber-signal-error "cancel" 'feature-not-implemented (car theirs-but-not-mine)))) (let (alist) (dolist (var vars) (let ((my-options (cdr (assoc var mine))) (their-options (cdr (assoc var theirs)))) (let ((common-options (intersection my-options their-options :test 'string=))) (if common-options ;; we have a match; but which one to use? ;; the first one will probably work (setq alist (cons (list var (car common-options)) alist)) ;; no match (jabber-signal-error "modify" 'not-acceptable var))))) alist))) (provide 'jabber-feature-neg) ;;; arch-tag: 65b2cdcc-7a5f-476b-a613-84ec8e590186 emacs-jabber-0.8.0/jabber-festival.el0000644000175100017510000000225711133727374014355 00000000000000;;; jabber-festival.el --- Festival alert hooks ;; Copyright (C) 2005 Magnus Henoch ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. (eval-when-compile (require 'jabber-alert)) (condition-case e (progn ;; Most people don't have Festival, so this will often fail (require 'festival) (define-jabber-alert festival "Voice messages through Festival" 'festival-say-string)) (error nil)) (provide 'jabber-festival) ;; arch-tag: 8922D096-5D07-11D9-B4C2-000A95C2FCD0 emacs-jabber-0.8.0/jabber-ft-client.el0000644000175100017510000000507111133727374014422 00000000000000;; jabber-ft-client.el - send file transfer requests, by JEP-0096 ;; Copyright (C) 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'cl)) (require 'jabber-si-client) (require 'jabber-util) (require 'jabber-ft-common) (defun jabber-ft-send (jc jid filename desc) "Attempt to send FILENAME to JID." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Send file to: " nil nil nil 'full) (read-file-name "Send which file: " nil nil t) (jabber-read-with-input-method "Description (optional): "))) (if (zerop (length desc)) (setq desc nil)) (setq filename (expand-file-name filename)) (access-file filename "Couldn't open file") (let* ((attributes (file-attributes filename)) (size (nth 7 attributes)) (date (nth 5 attributes)) (hash (jabber-ft-get-md5 filename))) (jabber-si-initiate jc jid "http://jabber.org/protocol/si/profile/file-transfer" `(file ((xmlns . "http://jabber.org/protocol/si/profile/file-transfer") (name . ,(file-name-nondirectory filename)) (size . ,size) (date . ,(jabber-encode-time date)) ,@(when hash (list (cons 'hash hash)))) (desc () ,desc)) (lexical-let ((filename filename)) (lambda (jc jid sid send-data-function) (jabber-ft-do-send jid sid send-data-function filename)))))) (defun jabber-ft-do-send (jid sid send-data-function filename) (if (stringp send-data-function) (message "File sending failed: %s" send-data-function) (with-temp-buffer (insert-file-contents-literally filename) ;; Ever heard of buffering? (funcall send-data-function (buffer-string)) (message "File transfer completed"))) ;; File transfer is monodirectional, so ignore received data. #'ignore) (provide 'jabber-ft-client) ;;; arch-tag: fba686d5-37b5-4165-86c5-49b76fa0ea6e emacs-jabber-0.8.0/jabber-ft-common.el0000644000175100017510000000352211133727374014433 00000000000000;;; jabber-ft-common.el --- Common functions for sending and receiving files (JEP-0096) ;; Copyright (C) 2006, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. (defcustom jabber-ft-md5sum-program (or (when (executable-find "md5") (list (executable-find "md5") "-n")) (when (executable-find "md5sum") (list (executable-find "md5sum")))) "The program to use to calculate MD5 sums of files. The first item should be the name of the program, and the remaing items the arguments. The file name is appended as the last argument." :type '(repeat string) :group 'jabber) (defun jabber-ft-get-md5 (file-name) "Get MD5 sum of FILE-NAME, and return as hex string. Return nil if no MD5 summing program is available." (when jabber-ft-md5sum-program (with-temp-buffer (apply 'call-process (car jabber-ft-md5sum-program) nil t nil (append (cdr jabber-ft-md5sum-program) (list file-name))) ;; Output is "hexsum filename" (goto-char (point-min)) (forward-word 1) (buffer-substring (point-min) (point))))) (provide 'jabber-ft-common) ;; arch-tag: 1ce4cce0-8360-11da-a5ba-000a95c2fcd0 emacs-jabber-0.8.0/jabber-ft-server.el0000644000175100017510000001175111133727374014454 00000000000000;; jabber-ft-server.el - handle incoming file transfers, by JEP-0096 ;; Copyright (C) 2003, 2004, 2007 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-si-server) (require 'jabber-util) (defvar jabber-ft-sessions nil "Alist, where keys are (sid jid), and values are buffers of the files.") (defvar jabber-ft-size nil "Size of the file that is being downloaded") (defvar jabber-ft-md5-hash nil "MD5 hash of the file that is being downloaded") (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/si/profile/file-transfer") (add-to-list 'jabber-si-profiles (list "http://jabber.org/protocol/si/profile/file-transfer" 'jabber-ft-accept 'jabber-ft-server-connected)) (defun jabber-ft-accept (jc xml-data) "Receive IQ stanza containing file transfer request, ask user" (let* ((from (jabber-xml-get-attribute xml-data 'from)) (query (jabber-iq-query xml-data)) (si-id (jabber-xml-get-attribute query 'id)) ;; TODO: check namespace (file (car (jabber-xml-get-children query 'file))) (name (jabber-xml-get-attribute file 'name)) (size (jabber-xml-get-attribute file 'size)) (date (jabber-xml-get-attribute file 'date)) (md5-hash (jabber-xml-get-attribute file 'hash)) (desc (car (jabber-xml-node-children (car (jabber-xml-get-children file 'desc))))) (range (car (jabber-xml-get-children file 'range)))) (unless (and name size) ;; both name and size must be present (jabber-signal-error "modify" 'bad-request)) (let ((question (format "%s is sending you the file %s (%s bytes).%s Accept? " (jabber-jid-displayname from) name size (if (not (zerop (length desc))) (concat " Description: '" desc "'") "")))) (unless (yes-or-no-p question) (jabber-signal-error "cancel" 'forbidden))) ;; default is to save with given name, in current directory. ;; maybe that's bad; maybe should be customizable. (let* ((file-name (read-file-name "Download to: " nil nil nil name)) (buffer (create-file-buffer file-name))) (message "Starting download of %s..." (file-name-nondirectory file-name)) (with-current-buffer buffer (kill-all-local-variables) (setq buffer-file-coding-system 'binary) ;; For Emacs, switch buffer to unibyte _before_ anything goes into it, ;; otherwise binary files are corrupted. For XEmacs, it isn't needed, ;; and it also doesn't have set-buffer-multibyte. (if (fboundp 'set-buffer-multibyte) (set-buffer-multibyte nil)) (set-visited-file-name file-name t) (set (make-local-variable 'jabber-ft-size) (string-to-number size)) (set (make-local-variable 'jabber-ft-md5-hash) md5-hash)) (add-to-list 'jabber-ft-sessions (cons (list si-id from) buffer))) ;; to support range, return something sensible here nil)) (defun jabber-ft-server-connected (jc jid sid send-data-function) ;; We don't really care about the send-data-function. But if it's ;; a string, it means that we have no connection. (if (stringp send-data-function) (message "File receiving failed: %s" send-data-function) ;; On success, we just return our data receiving function. 'jabber-ft-data)) (defun jabber-ft-data (jc jid sid data) "Receive chunk of transferred file." (let ((buffer (cdr (assoc (list sid jid) jabber-ft-sessions)))) (with-current-buffer buffer ;; If data is nil, there is no more data. ;; But maybe the remote entity doesn't close the stream - ;; then we have to keep track of file size to know when to stop. ;; Return value is whether to keep connection open. (when data (insert data)) (if (and data (< (buffer-size) jabber-ft-size)) t (basic-save-buffer) (if (and jabber-ft-md5-hash (let ((file-hash (jabber-ft-get-md5 buffer-file-name))) (and file-hash (not (string= file-hash jabber-ft-md5-hash))))) ;; hash mismatch! (progn (message "%s downloaded - CHECKSUM MISMATCH!" (file-name-nondirectory buffer-file-name)) (sleep-for 5)) ;; all is fine (message "%s downloaded" (file-name-nondirectory buffer-file-name))) (kill-buffer buffer) nil)))) (provide 'jabber-ft-server) ;;; arch-tag: 334adcff-6210-496e-8382-8f49ae0248a1 emacs-jabber-0.8.0/jabber-gmail.el0000644000175100017510000000741311133727374013630 00000000000000;;; jabber-gmail.el --- Gmail notifications via emacs-jabber ;; Copyright (C) 2008 Magnus Henoch ;; Copyright (C) 2007 Valery V. Vorotyntsev ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License ;; as published by the Free Software Foundation; either version 2 ;; of the License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Usage: ;; Add the following line to your ~/.emacs: ;; ;; (require 'jabber-gmail) ;; ;; If you prefer on demand loading ;; [http://a-nickels-worth.blogspot.com/2007/11/effective-emacs.html]: ;; ;; (autoload 'jabber-gmail-query "jabber-gmail") ;; (autoload 'jabber-gmail-subscribe "jabber-gmail") ;; (add-hook 'jabber-post-connect-hook 'jabber-gmail-subscribe) ;; ;; You may wish to bind a shortcut for `jabber-gmail-query' ;; ;; (global-set-key (kbd " g") 'jabber-gmail-query) ;; ;; or to customize `jabber-gmail-dothreads' ;; ;; (defun jabber-gmail-dothreads (ts) ;; (let ((msg (format "%d new messages in gmail inbox" (length ts)))) ;; (message msg) ;; (jabber-screen-message msg))) ;;;###autoload (defun jabber-gmail-subscribe (jc) "Subscribe to gmail notifications. See http://code.google.com/apis/talk/jep_extensions/usersettings.html#4" (interactive (list (jabber-read-account))) (jabber-send-iq jc (jabber-connection-bare-jid jc) "set" '(usersetting ((xmlns . "google:setting")) (mailnotifications ((value . "true")))) #'jabber-report-success "Gmail subscription" #'jabber-process-data "Gmail subscription") ;; Looks like "one shot" request is still needed to activate ;; notifications machinery. (jabber-gmail-query jc)) (add-to-list 'jabber-iq-set-xmlns-alist (cons "google:mail:notify" #'jabber-gmail-process-new-mail)) (defun jabber-gmail-process-new-mail (jc xml-sexp) "Process new gmail notification. See http://code.google.com/apis/talk/jep_extensions/gmail.html#notifications" (let ((from (jabber-xml-get-attribute xml-sexp 'from)) (id (jabber-xml-get-attribute xml-sexp 'id))) ;; respond to server (jabber-send-iq jc from "result" nil nil nil nil nil id)) (jabber-gmail-query jc)) ;;;###autoload (defun jabber-gmail-query (jc) "Request mail information from the Google Talk server (a.k.a. one shot query). See http://code.google.com/apis/talk/jep_extensions/gmail.html#requestmail" (interactive (list (jabber-read-account))) (jabber-send-iq jc (jabber-connection-bare-jid jc) "get" '(query ((xmlns . "google:mail:notify"))) #'jabber-gmail-process-mailbox nil #'jabber-process-data "Gmail query" "gmail-query")) (defun jabber-gmail-process-mailbox (jc xml-sexp &rest ignore) "Process gmail query response. See http://code.google.com/apis/talk/jep_extensions/gmail.html#response" (let ((ts (jabber-xml-node-children (car (jabber-xml-get-children xml-sexp 'mailbox))))) (when ts (jabber-gmail-dothreads ts)))) (defun jabber-gmail-dothreads (threads) "Process elements. THREADS is a list of XML sexps, corresponding to elements. See http://code.google.com/apis/talk/jep_extensions/gmail.html#response" (message "%d new messages in gmail inbox" (length threads))) (provide 'jabber-gmail) ;; arch-tag: 102bc8e4-e08f-11dc-ab66-000a95c2fcd0 emacs-jabber-0.8.0/jabber-history.el0000644000175100017510000002666711133727374014254 00000000000000;; jabber-history.el - recording message history ;; Copyright (C) 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2004 - Mathias Dahl ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; Log format: ;; Each message is on one separate line, represented as a vector with ;; five elements. The first element is time encoded according to ;; JEP-0082. The second element is direction, "in" or "out". ;; The third element is the sender, "me" or a JID. The fourth ;; element is the recipient. The fifth element is the text ;; of the message. ;; FIXME: when rotation is enabled, jabber-history-query won't look ;; for older history files if the current history file doesn't contain ;; enough backlog entries. (require 'jabber-core) (require 'jabber-util) (require 'jabber-autoloads) (defgroup jabber-history nil "Customization options for Emacs Jabber history files." :group 'jabber) (defcustom jabber-history-enabled nil "Non-nil means message logging is enabled." :type 'boolean :group 'jabber-history) (defcustom jabber-use-global-history t "Indicate whether Emacs Jabber should use a global file for store messages. If non-nil, jabber-global-history-filename is used, otherwise, messages are stored in per-user files under the jabber-history-dir directory." :type 'boolean :group 'jabber-history) (defcustom jabber-history-dir "~/.emacs-jabber" "Base directory where per-contact history files are stored. Used only when jabber-use-global-history is not true." :type 'directory :group 'jabber-history) (defcustom jabber-global-history-filename "~/.jabber_global_message_log" "Global file where all messages are logged. Used when jabber-use-global-history is non-nil." :type 'file :group 'jabber-history) (defcustom jabber-history-enable-rotation nil "Whether history files should be renamed when reach jabber-history-size-limit kilobytes. If nil, history files will grow indefinitely, otherwise they'll be renamed to -, where is 1 or the smallest number after the last rotation." :type 'boolean :group 'jabber-history) (defcustom jabber-history-size-limit 1024 "Maximum history file size in kilobytes. When history file reaches this limit, it is renamed to -, where is 1 or the smallest number after the last rotation." :type 'integer :group 'jabber-history) (defun jabber-rotate-history-p (history-file) "Return true if HISTORY-FILE should be rotated." (when (and jabber-history-enable-rotation (file-exists-p history-file)) (> (/ (nth 7 (file-attributes history-file)) 1024) jabber-history-size-limit))) (defun jabber-history-rotate (history-file &optional try) "Rename HISTORY-FILE to HISTORY-FILE-TRY." (let ((suffix (number-to-string (or try 1)))) (if (file-exists-p (concat history-file "-" suffix)) (jabber-history-rotate history-file (if try (1+ try) 1)) (rename-file history-file (concat history-file "-" suffix))))) (add-to-list 'jabber-message-chain 'jabber-message-history) (defun jabber-message-history (jc xml-data) "Log message to log file." (when (and (not jabber-use-global-history) (not (file-directory-p jabber-history-dir))) (make-directory jabber-history-dir)) (if (and jabber-history-enabled (not (jabber-muc-message-p xml-data))) (let ((from (jabber-xml-get-attribute xml-data 'from)) (text (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'body))))) (timestamp (car (delq nil (mapcar 'jabber-x-delay (jabber-xml-get-children xml-data 'x)))))) (when (and from text) (jabber-history-log-message "in" from nil text timestamp))))) (add-hook 'jabber-chat-send-hooks 'jabber-history-send-hook) (defun jabber-history-send-hook (body id) "Log outgoing message to log file." (when (and (not jabber-use-global-history) (not (file-directory-p jabber-history-dir))) (make-directory jabber-history-dir)) ;; This function is called from a chat buffer, so jabber-chatting-with ;; contains the desired value. (if jabber-history-enabled (jabber-history-log-message "out" nil jabber-chatting-with body (current-time)))) (defun jabber-history-filename (contact) "Return a history filename for CONTACT if the per-user file loggin strategy is used or the global history filename." (if jabber-use-global-history jabber-global-history-filename ;; jabber-jid-symbol is the best canonicalization we have. (concat jabber-history-dir "/" (symbol-name (jabber-jid-symbol contact))))) (defun jabber-history-log-message (direction from to body timestamp) "Log a message" (with-temp-buffer ;; Remove properties (set-text-properties 0 (length body) nil body) ;; Encode text as Lisp string - get decoding for free (setq body (prin1-to-string body)) ;; Encode LF and CR (while (string-match "\n" body) (setq body (replace-match "\\n" nil t body nil))) (while (string-match "\r" body) (setq body (replace-match "\\r" nil t body nil))) (insert (format "[\"%s\" \"%s\" %s %s %s]\n" (jabber-encode-time (or timestamp (current-time))) (or direction "in") (or (when from (prin1-to-string from)) "\"me\"") (or (when to (prin1-to-string to)) "\"me\"") body)) (let ((coding-system-for-write 'utf-8) (history-file (jabber-history-filename (or from to)))) (when (and (not jabber-use-global-history) (not (file-directory-p jabber-history-dir))) (make-directory jabber-history-dir)) (when (jabber-rotate-history-p history-file) (jabber-history-rotate history-file)) (condition-case e (write-region (point-min) (point-max) history-file t 'quiet) (error (message "Unable to write history: %s" (error-message-string e))))))) (defun jabber-history-query (start-time end-time number direction jid-regexp history-file) "Return a list of vectors, one for each message matching the criteria. START-TIME and END-TIME are floats as obtained from `float-time'. Either or both may be nil, meaning no restriction. NUMBER is the maximum number of messages to return, or t for unlimited. DIRECTION is either \"in\" or \"out\", or t for no limit on direction. JID-REGEXP is a regexp which must match the JID. HISTORY-FILE is the file in which to search. Currently jabber-history-query performs a linear search from the end of the log file." (when (file-readable-p history-file) (with-temp-buffer (let ((coding-system-for-read 'utf-8)) (if jabber-use-global-history (insert-file-contents history-file) (let* ((lines-collected nil) (matched-files (directory-files jabber-history-dir t (file-name-nondirectory history-file))) (matched-files (cons (car matched-files) (sort (cdr matched-files) 'string>-numerical)))) (while (not lines-collected) (if (null matched-files) (setq lines-collected t) (let ((file (pop matched-files))) (progn (insert-file-contents file) (if (>= (count-lines (point-min) (point-max)) number) (setq lines-collected t))))))))) (let (collected current-line) (goto-char (point-max)) (catch 'beginning-of-file (while (progn (backward-sexp) (setq current-line (car (read-from-string (buffer-substring (point) (save-excursion (forward-sexp) (point)))))) (and (or (null start-time) (> (jabber-float-time (jabber-parse-time (aref current-line 0))) start-time)) (or (eq number t) (< (length collected) number)))) (if (and (or (eq direction t) (string= direction (aref current-line 1))) (or (null end-time) (> end-time (jabber-float-time (jabber-parse-time (aref current-line 0))))) (string-match jid-regexp (car (remove "me" (list (aref current-line 2) (aref current-line 3)))))) (push current-line collected)) (when (bobp) (throw 'beginning-of-file nil)))) collected)))) (defcustom jabber-backlog-days 3.0 "Age limit on messages in chat buffer backlog, in days" :group 'jabber :type '(choice (number :tag "Number of days") (const :tag "No limit" nil))) (defcustom jabber-backlog-number 10 "Maximum number of messages in chat buffer backlog" :group 'jabber :type 'integer) (defun jabber-history-backlog (jid &optional before) "Fetch context from previous chats with JID. Return a list of history entries (vectors), limited by `jabber-backlog-days' and `jabber-backlog-number'. If BEFORE is non-nil, it should be a float-time after which no entries will be fetched. `jabber-backlog-days' still applies, though." (jabber-history-query (and jabber-backlog-days (- (jabber-float-time) (* jabber-backlog-days 86400.0))) before jabber-backlog-number t ; both incoming and outgoing (concat "^" (regexp-quote (jabber-jid-user jid)) "\\(/.*\\)?$") (jabber-history-filename jid))) (defun jabber-history-move-to-per-user () "Migrate global history to per-user files." (interactive) (when (file-directory-p jabber-history-dir) (error "Per-user history directory already exists")) (make-directory jabber-history-dir) (let ((jabber-use-global-history nil)) (with-temp-buffer (let ((coding-system-for-read 'utf-8)) (insert-file-contents jabber-global-history-filename)) (let ((progress-reporter (when (fboundp 'make-progress-reporter) (make-progress-reporter "Migrating history..." (point-min) (point-max)))) ;;(file-table (make-hash-table :test 'equal)) ;; Keep track of blocks of entries pertaining to the same JID. current-jid jid-start) (while (not (eobp)) (let* ((start (point)) (end (progn (forward-line) (point))) (line (buffer-substring start end)) (parsed (car (read-from-string line))) (jid (if (string= (aref parsed 2) "me") (aref parsed 3) (aref parsed 2)))) ;; Whenever there is a change in JID... (when (not (equal jid current-jid)) (when current-jid ;; ...save data for previous JID... (let ((history-file (jabber-history-filename current-jid))) (write-region jid-start start history-file t 'quiet))) ;; ...and switch to new JID. (setq current-jid jid) (setq jid-start start)) (when (fboundp 'progress-reporter-update) (progress-reporter-update progress-reporter (point))))) ;; Finally, save the last block, if any. (when current-jid (let ((history-file (jabber-history-filename current-jid))) (write-region jid-start (point-max) history-file t 'quiet)))))) (message "Done. Please change `jabber-use-global-history' now.")) (provide 'jabber-history) ;; arch-tag: 0AA0C235-3FC0-11D9-9FE7-000A95C2FCD0 emacs-jabber-0.8.0/jabber-iq.el0000644000175100017510000001717611133727374013157 00000000000000;; jabber-iq.el - infoquery functions ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-core) (require 'jabber-util) (require 'jabber-keymap) (defvar *jabber-open-info-queries* nil "an alist of open query id and their callback functions") (defvar jabber-iq-get-xmlns-alist nil "Mapping from XML namespace to handler for IQ GET requests.") (defvar jabber-iq-set-xmlns-alist nil "Mapping from XML namespace to handler for IQ SET requests.") (defvar jabber-browse-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map jabber-common-keymap) (define-key map [mouse-2] 'jabber-popup-combined-menu) map)) (defcustom jabber-browse-mode-hook nil "Hook run when entering Browse mode." :group 'jabber :type 'hook) (defgroup jabber-browse nil "browse display options" :group 'jabber) (defcustom jabber-browse-buffer-format "*-jabber-browse:-%n-*" "The format specification for the name of browse buffers. These fields are available at this moment: %n JID to browse" :type 'string :group 'jabber-browse) (defun jabber-browse-mode () "\\{jabber-browse-mode-map}" (kill-all-local-variables) (setq major-mode 'jabber-browse-mode mode-name "jabber-browse") (use-local-map jabber-browse-mode-map) (setq buffer-read-only t) (if (fboundp 'run-mode-hooks) (run-mode-hooks 'jabber-browse-mode-hook) (run-hooks 'jabber-browse-mode-hook))) (put 'jabber-browse-mode 'mode-class 'special) (add-to-list 'jabber-iq-chain 'jabber-process-iq) (defun jabber-process-iq (jc xml-data) "process an incoming iq stanza" (let* ((id (jabber-xml-get-attribute xml-data 'id)) (type (jabber-xml-get-attribute xml-data 'type)) (from (jabber-xml-get-attribute xml-data 'from)) (query (jabber-iq-query xml-data)) (callback (assoc id *jabber-open-info-queries*))) (cond ;; if type is "result" or "error", this is a response to a query we sent. ((or (string= type "result") (string= type "error")) (let ((callback-cons (nth (cdr (assoc type '(("result" . 0) ("error" . 1)))) (cdr callback)))) (if (consp callback-cons) (funcall (car callback-cons) jc xml-data (cdr callback-cons)))) (setq *jabber-open-info-queries* (delq callback *jabber-open-info-queries*))) ;; if type is "get" or "set", correct action depends on namespace of request. ((and (listp query) (or (string= type "get") (string= type "set"))) (let* ((which-alist (eval (cdr (assoc type (list (cons "get" 'jabber-iq-get-xmlns-alist) (cons "set" 'jabber-iq-set-xmlns-alist)))))) (handler (cdr (assoc (jabber-xml-get-attribute query 'xmlns) which-alist)))) (if handler (condition-case error-var (funcall handler jc xml-data) (jabber-error (apply 'jabber-send-iq-error jc from id query (cdr error-var))) (error (jabber-send-iq-error jc from id query "wait" 'internal-server-error (error-message-string error-var)))) (jabber-send-iq-error jc from id query "cancel" 'feature-not-implemented))))))) (defun jabber-send-iq (jc to type query success-callback success-closure-data error-callback error-closure-data &optional result-id) "Send an iq stanza to the specified entity, and optionally set up a callback. JC is the Jabber connection. TO is the addressee. TYPE is one of \"get\", \"set\", \"result\" or \"error\". QUERY is a list containing the child of the iq node in the format `jabber-sexp2xml' accepts. SUCCESS-CALLBACK is the function to be called when a successful result arrives. SUCCESS-CLOSURE-DATA is an extra argument to SUCCESS-CALLBACK. ERROR-CALLBACK is the function to be called when an error arrives. ERROR-CLOSURE-DATA is an extra argument to ERROR-CALLBACK. RESULT-ID is the id to be used for a response to a received iq message. `jabber-report-success' and `jabber-process-data' are common callbacks. The callback functions are called like this: \(funcall CALLBACK JC XML-DATA CLOSURE-DATA) with XML-DATA being the IQ stanza received in response. " (let ((id (or result-id (apply 'format "emacs-iq-%d.%d.%d" (current-time))))) (if (or success-callback error-callback) (setq *jabber-open-info-queries* (cons (list id (cons success-callback success-closure-data) (cons error-callback error-closure-data)) *jabber-open-info-queries*))) (jabber-send-sexp jc (list 'iq (append (if to (list (cons 'to to))) (list (cons 'type type)) (list (cons 'id id))) query)))) (defun jabber-send-iq-error (jc to id original-query error-type condition &optional text app-specific) "Send an error iq stanza to the specified entity in response to a previously sent iq stanza. TO is the addressee. ID is the id of the iq stanza that caused the error. ORIGINAL-QUERY is the original query, which should be included in the error, or nil. ERROR-TYPE is one of \"cancel\", \"continue\", \"modify\", \"auth\" and \"wait\". CONDITION is a symbol denoting a defined XMPP condition. TEXT is a string to be sent in the error message, or nil for no text. APP-SPECIFIC is a list of extra XML tags. See section 9.3 of XMPP Core." (jabber-send-sexp jc `(iq ((to . ,to) (type . "error") (id . ,id)) ,original-query (error ((type . ,error-type)) (,condition ((xmlns . "urn:ietf:params:xml:ns:xmpp-stanzas"))) ,(if text `(text ((xmlns . "urn:ietf:params:xml:ns:xmpp-stanzas")) ,text)) ,@app-specific)))) (defun jabber-process-data (jc xml-data closure-data) "Process random results from various requests." (let ((from (or (jabber-xml-get-attribute xml-data 'from) (plist-get (fsm-get-state-data jc) :server))) (xmlns (jabber-iq-xmlns xml-data)) (type (jabber-xml-get-attribute xml-data 'type))) (with-current-buffer (get-buffer-create (format-spec jabber-browse-buffer-format (list (cons ?n from)))) (if (not (eq major-mode 'jabber-browse-mode)) (jabber-browse-mode)) (setq buffer-read-only nil) (goto-char (point-max)) (insert (jabber-propertize from 'face 'jabber-title-large) "\n\n") ;; Put point at beginning of data (save-excursion ;; If closure-data is a function, call it. If it is a string, ;; output it along with a description of the error. For other ;; values (e.g. nil), just dump the XML. (cond ((functionp closure-data) (funcall closure-data jc xml-data)) ((stringp closure-data) (insert closure-data ": " (jabber-parse-error (jabber-iq-error xml-data)) "\n\n")) (t (insert (format "%S\n\n" xml-data)))) (dolist (hook '(jabber-info-message-hooks jabber-alert-info-message-hooks)) (run-hook-with-args hook 'browse (current-buffer) (funcall jabber-alert-info-message-function 'browse (current-buffer)))))))) (provide 'jabber-iq) ;;; arch-tag: 5585dfa3-b59a-42ee-9292-803652c85e26 emacs-jabber-0.8.0/jabber-keepalive.el0000644000175100017510000001360411133727374014503 00000000000000;; jabber-keepalive.el - try to detect lost connection ;; Copyright (C) 2004, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2007 - Detlev Zundel - dzu@gnu.org ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;;; Keepalive - send something to the server and see if it answers ;;; ;;; These keepalive functions send a urn:xmpp:ping request to the ;;; server every X minutes, and considers the connection broken if ;;; they get no answer within Y seconds. ;;;###autoload (defgroup jabber-keepalive nil "Keepalive functions try to detect lost connection" :group 'jabber) ;;;###autoload (defcustom jabber-keepalive-interval 600 "Interval in seconds between connection checks." :type 'integer :group 'jabber-keepalive) ;;;###autoload (defcustom jabber-keepalive-timeout 20 "Seconds to wait for response from server." :type 'integer :group 'jabber-keepalive) (defvar jabber-keepalive-timer nil "Timer object for keepalive function") (defvar jabber-keepalive-timeout-timer nil "Timer object for keepalive timeout function") (defvar jabber-keepalive-pending nil "List of outstanding keepalive connections") (defvar jabber-keepalive-debug nil "Log keepalive traffic when non-nil") ;;;###autoload (defun jabber-keepalive-start (&optional jc) "Activate keepalive. That is, regularly send a ping request to the server, and disconnect if it doesn't answer. See `jabber-keepalive-interval' and `jabber-keepalive-timeout'. The JC argument makes it possible to add this function to `jabber-post-connect-hooks'; it is ignored. Keepalive is activated for all accounts regardless of the argument." (interactive) (when jabber-keepalive-timer (jabber-keepalive-stop)) (setq jabber-keepalive-timer (run-with-timer 5 jabber-keepalive-interval 'jabber-keepalive-do)) (add-hook 'jabber-post-disconnect-hook 'jabber-keepalive-stop)) (defun jabber-keepalive-stop () "Deactivate keepalive" (interactive) (when jabber-keepalive-timer (jabber-cancel-timer jabber-keepalive-timer) (setq jabber-keepalive-timer nil))) (defun jabber-keepalive-do () (when jabber-keepalive-debug (message "%s: sending keepalive packet(s)" (current-time-string))) (setq jabber-keepalive-timeout-timer (run-with-timer jabber-keepalive-timeout nil 'jabber-keepalive-timeout)) (setq jabber-keepalive-pending jabber-connections) (dolist (c jabber-connections) ;; Whether we get an error or not is not interesting. ;; Getting a response at all is. (jabber-send-iq c nil "get" ;; "ping" is XEP-0199 '(query ((xmlns . "urn:xmpp:ping"))) 'jabber-keepalive-got-response nil 'jabber-keepalive-got-response nil))) (defun jabber-keepalive-got-response (jc &rest args) (when jabber-keepalive-debug (message "%s: got keepalive response from %s" (current-time-string) (plist-get (fsm-get-state-data jc) :server))) (setq jabber-keepalive-pending (remq jc jabber-keepalive-pending)) (when (null jabber-keepalive-pending) (jabber-cancel-timer jabber-keepalive-timeout-timer) (setq jabber-keepalive-timeout-timer nil))) (defun jabber-keepalive-timeout () (jabber-cancel-timer jabber-keepalive-timer) (setq jabber-keepalive-timer nil) (dolist (c jabber-keepalive-pending) (message "%s: keepalive timeout, connection to %s considered lost" (current-time-string) (plist-get (fsm-get-state-data c) :server)) (run-hooks jabber-lost-connection-hooks c) (jabber-disconnect-one c nil))) ;;;; Whitespace pings - less traffic, no error checking on our side ;;; ;;; Openfire needs something like this, but I couldn't bring myself to ;;; enable keepalive by default... Whitespace pings are light and ;;; unobtrusive. ;;;###autoload (defcustom jabber-whitespace-ping-interval 30 "Send a space character to the server with this interval, in seconds. This is a traditional remedy for a number of problems: to keep NAT boxes from considering the connection dead, to have the OS discover earlier that the connection is lost, and to placate servers which rely on the client doing this, e.g. Openfire. If you want to verify that the server is able to answer, see `jabber-keepalive-start' for another mechanism." :type '(integer :tag "Interval in seconds") :group 'jabber-core) (defvar jabber-whitespace-ping-timer nil "Timer object for whitespace pings") ;;;###autoload (defun jabber-whitespace-ping-start (&optional jc) "Start sending whitespace pings at regular intervals. See `jabber-whitespace-ping-interval'. The JC argument is ignored; whitespace pings are enabled for all accounts." (interactive) (when jabber-whitespace-ping-timer (jabber-whitespace-ping-stop)) (setq jabber-whitespace-ping-timer (run-with-timer 5 jabber-whitespace-ping-interval 'jabber-whitespace-ping-do)) (add-hook 'jabber-post-disconnect-hook 'jabber-whitespace-ping-stop)) (defun jabber-whitespace-ping-stop () "Deactivate whitespace pings" (interactive) (when jabber-whitespace-ping-timer (jabber-cancel-timer jabber-whitespace-ping-timer) (setq jabber-whitespace-ping-timer nil))) (defun jabber-whitespace-ping-do () (dolist (c jabber-connections) (jabber-send-string c " "))) (provide 'jabber-keepalive) ;;; arch-tag: d19ca743-75a1-475f-9217-83bd18012146 emacs-jabber-0.8.0/jabber-keymap.el0000644000175100017510000000453211133727374014024 00000000000000;; jabber-keymap.el - common keymap for many modes ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;; button.el was introduced in Emacs 22 (condition-case e (require 'button) (error nil)) (defvar jabber-common-keymap (let ((map (make-sparse-keymap))) (define-key map "\C-c\C-c" 'jabber-popup-chat-menu) (define-key map "\C-c\C-r" 'jabber-popup-roster-menu) (define-key map "\C-c\C-i" 'jabber-popup-info-menu) (define-key map "\C-c\C-m" 'jabber-popup-muc-menu) (define-key map "\C-c\C-s" 'jabber-popup-service-menu) ;; note that {forward,backward}-button are not autoloaded. ;; thus the `require' above. (when (fboundp 'forward-button) (define-key map [?\t] 'forward-button) (define-key map [backtab] 'backward-button)) map)) ;;;###autoload (defvar jabber-global-keymap (let ((map (make-sparse-keymap))) (define-key map "\C-c" 'jabber-connect-all) (define-key map "\C-d" 'jabber-disconnect) (define-key map "\C-r" 'jabber-switch-to-roster-buffer) (define-key map "\C-j" 'jabber-chat-with) (define-key map "\C-l" 'jabber-activity-switch-to) (define-key map "\C-a" 'jabber-send-away-presence) (define-key map "\C-o" 'jabber-send-default-presence) (define-key map "\C-x" 'jabber-send-xa-presence) (define-key map "\C-p" 'jabber-send-presence) map) "Global Jabber keymap (usually under C-x C-j)") ;;;###autoload (define-key ctl-x-map "\C-j" jabber-global-keymap) (provide 'jabber-keymap) ;;; arch-tag: 22a9993d-a4a7-40ef-a025-7cff6c3f5587 emacs-jabber-0.8.0/jabber-logon.el0000644000175100017510000000617311133727374013657 00000000000000;; jabber-logon.el - logon functions ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-xml) (require 'jabber-util) ;; sha1-el is known under two names (condition-case e (require 'sha1) (error (require 'sha1-el))) (defun jabber-get-auth (jc to session-id) "Send IQ get request in namespace \"jabber:iq:auth\"." (jabber-send-iq jc to "get" `(query ((xmlns . "jabber:iq:auth")) (username () ,(plist-get (fsm-get-state-data jc) :username))) #'jabber-do-logon session-id #'jabber-report-success "Impossible error - auth field request")) (defun jabber-do-logon (jc xml-data session-id) "send username and password in logon attempt" (let* ((digest-allowed (jabber-xml-get-children (jabber-iq-query xml-data) 'digest)) (passwd (when (or digest-allowed (plist-get (fsm-get-state-data jc) :encrypted) (yes-or-no-p "Jabber server only allows cleartext password transmission! Continue? ")) (or (plist-get (fsm-get-state-data jc) :password) (jabber-read-password (jabber-connection-bare-jid jc))))) auth) (if (null passwd) (fsm-send jc :authentication-failure) (if digest-allowed (setq auth `(digest () ,(sha1 (concat session-id passwd)))) (setq auth `(password () ,passwd))) ;; For legacy authentication we must specify a resource. (unless (plist-get (fsm-get-state-data jc) :resource) ;; Yes, this is ugly. Where is my encapsulation? (plist-put (fsm-get-state-data jc) :resource "emacs-jabber")) (jabber-send-iq jc (plist-get (fsm-get-state-data jc) :server) "set" `(query ((xmlns . "jabber:iq:auth")) (username () ,(plist-get (fsm-get-state-data jc) :username)) ,auth (resource () ,(plist-get (fsm-get-state-data jc) :resource))) #'jabber-process-logon passwd #'jabber-process-logon nil)))) (defun jabber-process-logon (jc xml-data closure-data) "receive login success or failure, and request roster. CLOSURE-DATA should be the password on success and nil on failure." (if closure-data ;; Logon success (fsm-send jc (cons :authentication-success closure-data)) ;; Logon failure (jabber-report-success jc xml-data "Logon") (fsm-send jc :authentication-failure))) (provide 'jabber-logon) ;;; arch-tag: f24ebe5e-3420-44bb-af81-d4de21f378b0 emacs-jabber-0.8.0/jabber-menu.el0000644000175100017510000001214711250455045013474 00000000000000;; jabber-menu.el - menu definitions ;; Copyright (C) 2003, 2004, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-util) (require 'jabber-autoloads) (eval-when-compile (require 'cl)) ;;;###autoload (defvar jabber-menu (let ((map (make-sparse-keymap "jabber-menu"))) (define-key map [jabber-menu-connect] '("Connect" . jabber-connect-all)) (define-key map [jabber-menu-disconnect] '("Disconnect" . jabber-disconnect)) (define-key map [jabber-menu-roster] '("Switch to roster" . jabber-switch-to-roster-buffer)) (define-key map [jabber-menu-customize] '("Customize" . jabber-customize)) (define-key map [jabber-menu-info] '("Help" . jabber-info)) (define-key map [jabber-menu-status] (cons "Set Status" (make-sparse-keymap "set-status"))) (define-key map [jabber-menu-status jabber-menu-status-chat] '("Chatty" . (lambda () (interactive) (jabber-send-presence "chat" (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*) *jabber-current-priority*)))) (define-key map [jabber-menu-status jabber-menu-status-dnd] '("Do not Disturb" . (lambda () (interactive) (jabber-send-presence "dnd" (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*) *jabber-current-priority*)))) (define-key map [jabber-menu-status jabber-menu-status-xa] '("Extended Away" . jabber-send-xa-presence)) (define-key map [jabber-menu-status jabber-menu-status-away] '("Away" . jabber-send-away-presence)) (define-key map [jabber-menu-status jabber-menu-status-online] '("Online" . jabber-send-default-presence)) map)) ;;;###autoload (defcustom jabber-display-menu 'maybe "Decide whether the \"Jabber\" menu is displayed in the menu bar. If t, always display. If nil, never display. If maybe, display if any of `jabber-account-list' or `jabber-connections' is non-nil." :group 'jabber :type '(choice (const :tag "Never" nil) (const :tag "Always" t) (const :tag "When any accounts have been configured or connected" maybe))) (defun jabber-menu (&optional remove) "Put \"Jabber\" menu on menubar. With prefix argument, remove it." (interactive "P") (setq jabber-display-menu (if remove nil t)) (force-mode-line-update)) (make-obsolete 'jabber-menu "set the variable `jabber-display-menu' instead.") ;; This used to be: ;; (define-key-after global-map [menu-bar jabber-menu] ...) ;; but that doesn't work in Emacs 21. ;;;###autoload (define-key-after (lookup-key global-map [menu-bar]) [jabber-menu] (list 'menu-item "Jabber" jabber-menu :visible '(or (eq jabber-display-menu t) (and (eq jabber-display-menu 'maybe) (or jabber-account-list (bound-and-true-p jabber-connections)))))) (defvar jabber-jid-chat-menu nil "Menu items for chat menu") (defvar jabber-jid-info-menu nil "Menu item for info menu") (defvar jabber-jid-roster-menu nil "Menu items for roster menu") (defvar jabber-jid-muc-menu nil "Menu items for MUC menu") (defvar jabber-jid-service-menu nil "Menu items for service menu") (defun jabber-popup-menu (which-menu) "Popup specified menu" (let* ((mouse-event (and (listp last-input-event) last-input-event)) (choice (widget-choose "Actions" which-menu mouse-event))) (if mouse-event (mouse-set-point mouse-event)) (if choice (call-interactively choice)))) (defun jabber-popup-chat-menu () "Popup chat menu" (interactive) (jabber-popup-menu jabber-jid-chat-menu)) (defun jabber-popup-info-menu () "Popup info menu" (interactive) (jabber-popup-menu jabber-jid-info-menu)) (defun jabber-popup-roster-menu () "Popup roster menu" (interactive) (jabber-popup-menu jabber-jid-roster-menu)) (defun jabber-popup-muc-menu () "Popup MUC menu" (interactive) (jabber-popup-menu jabber-jid-muc-menu)) (defun jabber-popup-service-menu () "Popup service menu" (interactive) (jabber-popup-menu jabber-jid-service-menu)) (defun jabber-popup-combined-menu () "Popup combined menu" (interactive) (jabber-popup-menu (append jabber-jid-chat-menu jabber-jid-info-menu jabber-jid-roster-menu jabber-jid-muc-menu))) (provide 'jabber-menu) ;;; arch-tag: 5147f52f-de47-4348-86ff-b799d7a75e3f emacs-jabber-0.8.0/jabber-modeline.el0000644000175100017510000000663111250455045014325 00000000000000;; jabber-modeline.el - display jabber status in modeline ;; Copyright (C) 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-presence) (require 'jabber-alert) (eval-when-compile (require 'cl)) (defgroup jabber-mode-line nil "Display Jabber status in mode line" :group 'jabber) (defcustom jabber-mode-line-compact t "Count contacts in fewer categories for compact view" :group 'jabber-mode-line :type 'boolean) (defvar jabber-mode-line-string nil) (defvar jabber-mode-line-presence nil) (defvar jabber-mode-line-contacts nil) (defadvice jabber-send-presence (after jsp-update-mode-line (show status priority)) (jabber-mode-line-presence-update)) (defun jabber-mode-line-presence-update () (setq jabber-mode-line-presence (if (and jabber-connections (not *jabber-disconnecting*)) (cdr (assoc *jabber-current-show* jabber-presence-strings)) "Offline"))) (defun jabber-mode-line-count-contacts (&rest ignore) (let ((count (list (cons "chat" 0) (cons "" 0) (cons "away" 0) (cons "xa" 0) (cons "dnd" 0) (cons nil 0)))) (dolist (jc jabber-connections) (dolist (buddy (plist-get (fsm-get-state-data jc) :roster)) (when (assoc (get buddy 'show) count) (incf (cdr (assoc (get buddy 'show) count)))))) (setq jabber-mode-line-contacts (if jabber-mode-line-compact (format "(%d/%d/%d)" (+ (cdr (assoc "chat" count)) (cdr (assoc "" count))) (+ (cdr (assoc "away" count)) (cdr (assoc "xa" count)) (cdr (assoc "dnd" count))) (cdr (assoc nil count))) (apply 'format "(%d/%d/%d/%d/%d/%d)" (mapcar 'cdr count)))))) (define-minor-mode jabber-mode-line-mode "Toggle display of Jabber status in mode lines. Display consists of your own status, and six numbers meaning the number of chatty, online, away, xa, dnd and offline contacts, respectively." :global t :group 'jabber-mode-line (setq jabber-mode-line-string "") (or global-mode-string (setq global-mode-string '(""))) (if jabber-mode-line-mode (progn (add-to-list 'global-mode-string 'jabber-mode-line-string t) (setq jabber-mode-line-string (list " " 'jabber-mode-line-presence " " 'jabber-mode-line-contacts)) (put 'jabber-mode-line-string 'risky-local-variable t) (put 'jabber-mode-line-presence 'risky-local-variable t) (jabber-mode-line-presence-update) (jabber-mode-line-count-contacts) (ad-activate 'jabber-send-presence) (add-hook 'jabber-post-disconnect-hook 'jabber-mode-line-presence-update) (add-hook 'jabber-presence-hooks 'jabber-mode-line-count-contacts)))) (provide 'jabber-modeline) ;;; arch-tag: c03a7d3b-8811-49d4-b0e0-7ffd661d7925 emacs-jabber-0.8.0/jabber-muc-nick-completion.el0000644000175100017510000001532711133727374016417 00000000000000;;; jabber-muc-nick-completion.el --- Add nick completion abilyty to emacs-jabber ;; Copyright (C) 2008 - Terechkov Evgenii - evg@altlinux.org ;; Copyright (C) 2007, 2008 - Kirill A. Korinskiy - catap@catap.ru ;; Copyright (C) 2007 - Serguei Jidkov - jsv@e-mail.ru ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; User customizations here: (defcustom jabber-muc-completion-delimiter ": " "String to add to end of completion line." :type 'string :group 'jabber-chat) (defcustom jabber-muc-looks-personaling-symbols '("," ":" ">") "Symbols for personaling messages" :type '(repeat string) :group 'jabber-chat) (defcustom jabber-muc-personal-message-bonus (* 60 20) "Bonus for personal message, in seconds." :type 'integer :group 'jabber-chat) (defcustom jabber-muc-all-string "all" "String meaning all conference members (to insert in completion). Note that \":\" or alike not needed (it appended in other string)" :type 'string :group 'jabber-chat) ;;; History: ;; ;;; Code: (require 'cl) (require 'jabber-muc) (require 'hippie-exp) (defvar *jabber-muc-participant-last-speaking* nil "Global alist in form (group . ((member . time-of-last-speaking) ...) ...).") (defun modify-alist (key val alist) "Update of ALIST's element (KEY . VAL), possibly destructive." (let ((entry (assoc key alist))) (if (not entry) (acons key val alist) (setf (cdr entry) val) alist))) (defun jabber-my-nick (&optional group) "Return my jabber nick in GROUP." (let ((room (or group jabber-group))) (cdr (or (assoc room *jabber-active-groupchats*) (assoc room jabber-muc-default-nicknames))) )) ;;;###autoload (defun jabber-muc-looks-like-personal-p (message &optional group) "Return non-nil if jabber MESSAGE is addresed to me. Optional argument GROUP to look." (if message (string-match (concat "^" (jabber-my-nick group) (regexp-opt jabber-muc-looks-personaling-symbols)) message) nil)) (defun jabber-muc-nicknames () "List of conference participants, excluding self, or nil if we not in conference." (delete-if '(lambda (nick) (string= nick (jabber-my-nick))) (append (mapcar 'car (cdr (assoc jabber-group jabber-muc-participants))) (list jabber-muc-all-string)))) ;; TODO: optimize this function (defun jabber-muc-participant-update-activity (group nick time) "Updates NICK's time of last speaking in GROUP to TIME." (let* ((room-activity (cdr (assoc group *jabber-muc-participant-last-speaking*))) (old-time (or (cdr (assoc nick room-activity)) 0))) (when (> time old-time) (setq *jabber-muc-participant-last-speaking* (modify-alist group (modify-alist nick time room-activity) *jabber-muc-participant-last-speaking*))))) (defun jabber-muc-track-message-time (nick group buffer text proposed-alert) "Tracks time of NICK's last speaking in GROUP." (when nick (let ((time (float-time))) (jabber-muc-participant-update-activity group nick (if (jabber-muc-looks-like-personal-p text group) (+ time jabber-muc-personal-message-bonus) time))))) (defun jabber-sort-nicks (nicks group) "Return list of NICKS in GROUP, sorted." (let ((times (cdr (assoc group *jabber-muc-participant-last-speaking*)))) (flet ((fetch-time (nick) (or (assoc nick times) (cons nick 0))) (cmp (nt1 nt2) (let ((t1 (cdr nt1)) (t2 (cdr nt2))) (if (and (zerop t1) (zerop t2)) (string< (car nt1) (car nt2)) (> t1 t2))))) (mapcar 'car (sort (mapcar 'fetch-time nicks) 'cmp))))) (defun jabber-muc-beginning-of-line () "Return position of line begining." (save-excursion (if (looking-back jabber-muc-completion-delimiter) (backward-char (+ (length jabber-muc-completion-delimiter) 1))) (skip-syntax-backward "^-") (point))) ;;; One big hack: (defun jabber-muc-completion-delete-last-tried () "Delete last tried competion variand from line." (let ((last-tried (car he-tried-table))) (when last-tried (goto-char he-string-beg) (delete-char (length last-tried)) (ignore-errors (delete-char (length jabber-muc-completion-delimiter))) ))) (defun try-expand-jabber-muc (old) "Try to expand target nick in MUC according to last speaking time. OLD is last tried nickname." (unless jabber-chatting-with (unless old (let ((nicknames (jabber-muc-nicknames))) (he-init-string (jabber-muc-beginning-of-line) (point)) (setq he-expand-list (jabber-sort-nicks (all-completions he-search-string (mapcar 'list nicknames)) jabber-group)))) (setq he-expand-list (delete-if '(lambda (x) (he-string-member x he-tried-table)) he-expand-list)) (if (null he-expand-list) (progn (when old ;; here and later : its hack to workaround ;; he-substitute-string work which cant substitute empty ;; lines (if (string= he-search-string "") (jabber-muc-completion-delete-last-tried) (he-reset-string))) ()) (let ((subst (if (eq (line-beginning-position) (jabber-muc-beginning-of-line)) (concat (car he-expand-list) jabber-muc-completion-delimiter) (car he-expand-list)))) (if (not (string= he-search-string "")) (he-substitute-string subst) (jabber-muc-completion-delete-last-tried) (progn (insert subst) (if (looking-back (concat "^" (regexp-quote (car he-expand-list)))) (unless (looking-back (concat "^" (regexp-quote (car he-expand-list)) jabber-muc-completion-delimiter)) (insert jabber-muc-completion-delimiter))) ) )) (setq he-tried-table (cons (car he-expand-list) (cdr he-tried-table))) (setq he-expand-list (cdr he-expand-list)) t))) (add-hook 'jabber-muc-hooks 'jabber-muc-track-message-time) (fset 'jabber-muc-completion (make-hippie-expand-function '(try-expand-jabber-muc))) (define-key jabber-chat-mode-map [?\t] 'jabber-muc-completion) (provide 'jabber-muc-nick-completion) ;; arch-tag: 2a81ac72-d261-11dc-be91-000a95c2fcd0 ;;; jabber-muc-completion.el ends here emacs-jabber-0.8.0/jabber-muc.el0000644000175100017510000011353711250455045013321 00000000000000;; jabber-muc.el - advanced MUC functions ;; Copyright (C) 2003, 2004, 2007, 2008, 2009 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-chat) (require 'jabber-widget) (require 'jabber-newdisco) (require 'jabber-autoloads) (require 'cl) ;;;###autoload (defvar *jabber-active-groupchats* nil "alist of groupchats and nicknames Keys are strings, the bare JID of the room. Values are strings.") (defvar jabber-pending-groupchats (make-hash-table) "Hash table of groupchats and nicknames. Keys are JID symbols; values are strings. This table records the last nickname used to join the particular chat room. Items are thus never removed.") (defvar jabber-muc-participants nil "alist of groupchats and participants Keys are strings, the bare JID of the room. Values are lists of nickname strings.") (defvar jabber-group nil "the groupchat you are participating in") (defvar jabber-muc-topic "" "The topic of the current MUC room.") (defvar jabber-role-history () "Keeps track of previously used roles") (defvar jabber-affiliation-history () "Keeps track of previously used affiliations") (defvar jabber-muc-nickname-history () "Keeps track of previously referred-to nicknames") ;;;###autoload (defcustom jabber-muc-default-nicknames nil "Default nickname for specific MUC rooms." :group 'jabber-chat :type '(repeat (cons :format "%v" (string :tag "JID of room") (string :tag "Nickname")))) ;;;###autoload (defcustom jabber-muc-autojoin nil "List of MUC rooms to automatically join on connection. This list is saved in your Emacs customizations. You can also store such a list on the Jabber server, where it is available to every client; see `jabber-edit-bookmarks'." :group 'jabber-chat :type '(repeat (string :tag "JID of room"))) (defcustom jabber-muc-disable-disco-check nil "If non-nil, disable checking disco#info of rooms before joining them. Disco information can tell whether the room exists and whether it is password protected, but some servers do not support it. If you want to join chat rooms on such servers, set this variable to t." :group 'jabber-chat :type 'boolean) (defcustom jabber-groupchat-buffer-format "*-jabber-groupchat-%n-*" "The format specification for the name of groupchat buffers. These fields are available (all are about the group you are chatting in): %n Roster name of group, or JID if no nickname set %j Bare JID (without resource)" :type 'string :group 'jabber-chat) (defcustom jabber-groupchat-prompt-format "[%t] %n> " "The format specification for lines in groupchat. These fields are available: %t Time, formatted according to `jabber-chat-time-format' %n, %u, %r Nickname in groupchat %j Full JID (room@server/nick)" :type 'string :group 'jabber-chat) (defcustom jabber-muc-header-line-format '(" " (:eval (jabber-jid-displayname jabber-group)) "\t" jabber-muc-topic) "The specification for the header line of MUC buffers. The format is that of `mode-line-format' and `header-line-format'." :type 'sexp :group 'jabber-chat) (defcustom jabber-muc-private-buffer-format "*-jabber-muc-priv-%g-%n-*" "The format specification for the buffer name for private MUC messages. These fields are available: %g Roster name of group, or JID if no nickname set %n Nickname of the group member you're chatting with" :type 'string :group 'jabber-chat) (defcustom jabber-muc-private-foreign-prompt-format "[%t] %g/%n> " "The format specification for lines others type in a private MUC buffer. These fields are available: %t Time, formatted according to `jabber-chat-time-format' %n Nickname in room %g Short room name (either roster name or username part of JID)" :type 'string :group 'jabber-chat) (defcustom jabber-muc-private-header-line-format '(" " (:eval (jabber-jid-resource jabber-chatting-with)) " in " (:eval (jabber-jid-displayname (jabber-jid-user jabber-chatting-with))) "\t" jabber-events-message "\t" jabber-chatstates-message) "The specification for the header line of private MUC chat buffers. The format is that of `mode-line-format' and `header-line-format'." :type 'sexp :group 'jabber-chat) ;;;###autoload (defvar jabber-muc-printers '() "List of functions that may be able to print part of a MUC message. This gets prepended to `jabber-chat-printers', which see.") ;;;###autoload (defun jabber-muc-get-buffer (group) "Return the chat buffer for chatroom GROUP. Either a string or a buffer is returned, so use `get-buffer' or `get-buffer-create'." (format-spec jabber-groupchat-buffer-format (list (cons ?n (jabber-jid-displayname group)) (cons ?j (jabber-jid-user group))))) (defun jabber-muc-create-buffer (jc group) "Prepare a buffer for chatroom GROUP. This function is idempotent." (with-current-buffer (get-buffer-create (jabber-muc-get-buffer group)) (unless (eq major-mode 'jabber-chat-mode) (jabber-chat-mode jc #'jabber-chat-pp)) ;; Make sure the connection variable is up to date. (setq jabber-buffer-connection jc) (set (make-local-variable 'jabber-group) group) (make-local-variable 'jabber-muc-topic) (setq jabber-send-function 'jabber-muc-send) (setq header-line-format jabber-muc-header-line-format) (current-buffer))) ;;;###autoload (defun jabber-muc-private-get-buffer (group nickname) "Return the chat buffer for private chat with NICKNAME in GROUP. Either a string or a buffer is returned, so use `get-buffer' or `get-buffer-create'." (format-spec jabber-muc-private-buffer-format (list (cons ?g (jabber-jid-displayname group)) (cons ?n nickname)))) (defun jabber-muc-private-create-buffer (jc group nickname) "Prepare a buffer for chatting with NICKNAME in GROUP. This function is idempotent." (with-current-buffer (get-buffer-create (jabber-muc-private-get-buffer group nickname)) (unless (eq major-mode 'jabber-chat-mode) (jabber-chat-mode jc #'jabber-chat-pp)) (set (make-local-variable 'jabber-chatting-with) (concat group "/" nickname)) (setq jabber-send-function 'jabber-chat-send) (setq header-line-format jabber-muc-private-header-line-format) (current-buffer))) (defun jabber-muc-send (jc body) "Send BODY to MUC room in current buffer." ;; There is no need to display the sent message in the buffer, as ;; we will get it back from the MUC server. (jabber-send-sexp jc `(message ((to . ,jabber-group) (type . "groupchat")) (body () ,body)))) (defun jabber-muc-add-groupchat (group nickname) "Remember participating in GROUP under NICKNAME." (let ((whichgroup (assoc group *jabber-active-groupchats*))) (if whichgroup (setcdr whichgroup nickname) (add-to-list '*jabber-active-groupchats* (cons group nickname))))) (defun jabber-muc-remove-groupchat (group) "Remove GROUP from internal bookkeeping." (let ((whichgroup (assoc group *jabber-active-groupchats*)) (whichparticipants (assoc group jabber-muc-participants))) (setq *jabber-active-groupchats* (delq whichgroup *jabber-active-groupchats*)) (setq jabber-muc-participants (delq whichparticipants jabber-muc-participants)))) (defun jabber-muc-participant-plist (group nickname) "Return plist associated with NICKNAME in GROUP. Return nil if nothing known about that combination." (let ((whichparticipants (assoc group jabber-muc-participants))) (when whichparticipants (cdr (assoc nickname whichparticipants))))) (defun jabber-muc-modify-participant (group nickname new-plist) "Assign properties in NEW-PLIST to NICKNAME in GROUP." (let ((participants (assoc group jabber-muc-participants))) ;; either we have a list of participants already... (if participants (let ((participant (assoc nickname participants))) ;; and maybe this participant is already in the list (if participant ;; if so, just update role, affiliation, etc. (setf (cdr participant) new-plist) (push (cons nickname new-plist) (cdr participants)))) ;; or we don't (push (cons group (list (cons nickname new-plist))) jabber-muc-participants)))) (defun jabber-muc-report-delta (nickname old-plist new-plist reason actor) "Compare OLD-PLIST and NEW-PLIST, and return a string explaining the change. Return nil if nothing noteworthy has happened. NICKNAME is the user experiencing the change. REASON and ACTOR, if non-nil, are the corresponding presence fields. This function is only concerned with presence stanzas resulting in the user entering/staying in the room." ;; The keys in the plist are affiliation, role and jid. (when (plist-get new-plist 'jid) ;; nickname is only used for displaying, so we can modify it if we ;; want to. (setq nickname (concat nickname " <" (jabber-jid-user (plist-get new-plist 'jid)) ">"))) (cond ((null old-plist) ;; User enters the room (concat nickname " enters the room (" (plist-get new-plist 'role) (unless (string= (plist-get new-plist 'affiliation) "none") (concat ", " (plist-get new-plist 'affiliation))) ")")) ;; If affiliation changes, the role change is usually the logical ;; one, so don't report it separately. ((not (string= (plist-get old-plist 'affiliation) (plist-get new-plist 'affiliation))) (let ((actor-reason (concat (when actor (concat " by " actor)) (when reason (concat ": " reason)))) (from (plist-get old-plist 'affiliation)) (to (plist-get new-plist 'affiliation))) ;; There are many ways to express these transitions in English. ;; This one favors eloquence over regularity and consistency. (cond ;; Higher affiliation ((or (and (member from '("outcast" "none" "member")) (member to '("admin" "owner"))) (and (string= from "admin") (string= to "owner"))) (concat nickname " has been promoted to " to actor-reason)) ;; Lower affiliation ((or (and (member from '("owner" "admin")) (string= to "member")) (and (string= from "owner") (string= to "admin"))) (concat nickname " has been demoted to " to actor-reason)) ;; Become member ((string= to "member") (concat nickname " has been granted membership" actor-reason)) ;; Lose membership ((string= to "none") (concat nickname " has been deprived of membership" actor-reason))))) ;; Role changes ((not (string= (plist-get old-plist 'role) (plist-get new-plist 'role))) (let ((actor-reason (concat (when actor (concat " by " actor)) (when reason (concat ": " reason)))) (from (plist-get old-plist 'role)) (to (plist-get new-plist 'role))) ;; Possible roles are "none" (not in room, hence not of interest ;; in this function), "visitor" (no voice), "participant" (has ;; voice), and "moderator". (cond ((string= to "moderator") (concat nickname " has been granted moderator privileges" actor-reason)) ((and (string= from "moderator") (string= to "participant")) (concat nickname " had moderator privileges revoked" actor-reason)) ((string= to "participant") (concat nickname " has been granted voice" actor-reason)) ((string= to "visitor") (concat nickname " has been denied voice" actor-reason))))))) (defun jabber-muc-remove-participant (group nickname) "Forget everything about NICKNAME in GROUP." (let ((participants (assoc group jabber-muc-participants))) (when participants (let ((participant (assoc nickname (cdr participants)))) (setf (cdr participants) (delq participant (cdr participants))))))) (defmacro jabber-muc-argument-list (&optional args) "Prepend connection and group name to ARGS. If the current buffer is not an MUC buffer, signal an error. This macro is meant for use as an argument to `interactive'." `(if (null jabber-group) (error "Not in MUC buffer") (nconc (list jabber-buffer-connection jabber-group) ,args))) (defun jabber-muc-read-completing (prompt &optional allow-not-joined) "Read the name of a joined chatroom, or use chatroom of current buffer, if any. If ALLOW-NOT-JOINED is provided and true, permit choosing any JID; only provide completion as a guide." (or jabber-group (jabber-read-jid-completing prompt (if (null *jabber-active-groupchats*) (error "You haven't joined any group") (mapcar (lambda (x) (jabber-jid-symbol (car x))) *jabber-active-groupchats*)) (not allow-not-joined) jabber-group))) (defun jabber-muc-read-nickname (group prompt) "Read the nickname of a participant in GROUP." (let ((nicknames (cdr (assoc group jabber-muc-participants)))) (unless nicknames (error "Unknown group: %s" group)) (completing-read prompt nicknames nil t nil 'jabber-muc-nickname-history))) (add-to-list 'jabber-jid-muc-menu (cons "Configure groupchat" 'jabber-groupchat-get-config)) (defun jabber-groupchat-get-config (jc group) "Ask for MUC configuration form" (interactive (jabber-muc-argument-list)) (jabber-send-iq jc group "get" '(query ((xmlns . "http://jabber.org/protocol/muc#owner"))) #'jabber-process-data #'jabber-groupchat-render-config #'jabber-process-data "MUC configuration request failed")) (defun jabber-groupchat-render-config (jc xml-data) "Render MUC configuration form" (let ((query (jabber-iq-query xml-data)) xdata) (dolist (x (jabber-xml-get-children query 'x)) (if (string= (jabber-xml-get-attribute x 'xmlns) "jabber:x:data") (setq xdata x))) (if (not xdata) (insert "No configuration possible.\n") (jabber-init-widget-buffer (jabber-xml-get-attribute xml-data 'from)) (setq jabber-buffer-connection jc) (jabber-render-xdata-form xdata) (widget-create 'push-button :notify #'jabber-groupchat-submit-config "Submit") (widget-insert "\t") (widget-create 'push-button :notify #'jabber-groupchat-cancel-config "Cancel") (widget-insert "\n") (widget-setup) (widget-minor-mode 1)))) (defun jabber-groupchat-submit-config (&rest ignore) "Submit MUC configuration form." (jabber-send-iq jabber-buffer-connection jabber-submit-to "set" `(query ((xmlns . "http://jabber.org/protocol/muc#owner")) ,(jabber-parse-xdata-form)) #'jabber-report-success "MUC configuration" #'jabber-report-success "MUC configuration")) (defun jabber-groupchat-cancel-config (&rest ignore) "Cancel MUC configuration form." (jabber-send-iq jabber-buffer-connection jabber-submit-to "set" '(query ((xmlns . "http://jabber.org/protocol/muc#owner")) (x ((xmlns . "jabber:x:data") (type . "cancel")))) nil nil nil nil)) (add-to-list 'jabber-jid-muc-menu (cons "Join groupchat" 'jabber-groupchat-join)) (defun jabber-groupchat-join (jc group nickname &optional popup) "join a groupchat, or change nick. In interactive calls, or if POPUP is true, switch to the groupchat buffer." (interactive (let ((account (jabber-read-account)) (group (jabber-read-jid-completing "group: "))) (list account group (jabber-muc-read-my-nickname account group) t))) ;; If the user is already in the room, we don't need as many checks. (if (or (assoc group *jabber-active-groupchats*) ;; Or if the users asked us not to check disco info. jabber-muc-disable-disco-check) (jabber-groupchat-join-3 jc group nickname nil popup) ;; Else, send a disco request to find out what we are connecting ;; to. (jabber-disco-get-info jc group nil #'jabber-groupchat-join-2 (list group nickname popup)))) (defun jabber-groupchat-join-2 (jc closure result) (destructuring-bind (group nickname popup) closure (let ( ;; Either success... (identities (car result)) (features (cadr result)) ;; ...or error (condition (when (eq (car result) 'error) (jabber-error-condition result)))) (cond ;; Maybe the room doesn't exist yet. ((eq condition 'item-not-found) (unless (y-or-n-p (format "%s doesn't exist. Create it? " (jabber-jid-displayname group))) (error "Non-existent groupchat"))) ;; Maybe the room doesn't support disco. ((eq condition 'feature-not-implemented) t ;whatever... ) ;; Maybe another error occurred. (condition (error "Couldn't query groupchat: %s" (jabber-parse-error result))) ;; Maybe it isn't a chat room. ((not (find "conference" identities :key (lambda (i) (aref i 1)) :test #'string=)) (error "%s is not a groupchat" (jabber-jid-displayname group)))) (let ((password ;; Is the room password-protected? (when (member "muc_passwordprotected" features) (or (jabber-get-conference-data jc group nil :password) (read-passwd (format "Password for %s: " (jabber-jid-displayname group))))))) (jabber-groupchat-join-3 jc group nickname password popup))))) (defun jabber-groupchat-join-3 (jc group nickname password popup) ;; Remember that this is a groupchat _before_ sending the stanza. ;; The response might come quicker than you think. (puthash (jabber-jid-symbol group) nickname jabber-pending-groupchats) (jabber-send-sexp jc `(presence ((to . ,(format "%s/%s" group nickname))) (x ((xmlns . "http://jabber.org/protocol/muc")) ,@(when password `((password () ,password)))) ,@(jabber-presence-children jc))) ;; There, stanza sent. Now we just wait for the MUC service to ;; mirror the stanza. This is handled in ;; `jabber-muc-process-presence', where a buffer will be created for ;; the room. ;; But if the user interactively asked to join, he/she probably ;; wants the buffer to pop up right now. (when popup (let ((buffer (jabber-muc-create-buffer jc group))) (switch-to-buffer buffer)))) (defun jabber-muc-read-my-nickname (jc group) "Read nickname for joining GROUP." (let ((default-nickname (or (jabber-get-conference-data jc group nil :nick) (cdr (assoc group jabber-muc-default-nicknames)) (plist-get (fsm-get-state-data jc) :username)))) (jabber-read-with-input-method (format "Nickname: (default %s) " default-nickname) nil nil default-nickname))) (add-to-list 'jabber-jid-muc-menu (cons "Change nickname" 'jabber-muc-nick)) (defalias 'jabber-muc-nick 'jabber-groupchat-join) (add-to-list 'jabber-jid-muc-menu (cons "Leave groupchat" 'jabber-groupchat-leave)) (defun jabber-groupchat-leave (jc group) "leave a groupchat" (interactive (jabber-muc-argument-list)) (let ((whichgroup (assoc group *jabber-active-groupchats*))) ;; send unavailable presence to our own nick in room (jabber-send-sexp jc `(presence ((to . ,(format "%s/%s" group (cdr whichgroup))) (type . "unavailable")))))) (add-to-list 'jabber-jid-muc-menu (cons "List participants" 'jabber-muc-names)) (defun jabber-muc-names () "Print names, affiliations, and roles of participants in current buffer." (interactive) (ewoc-enter-last jabber-chat-ewoc (list :notice (jabber-muc-print-names (cdr (assoc jabber-group jabber-muc-participants))) :time (current-time)))) (defun jabber-muc-print-names (participants) "Format and return data in PARTICIPANTS." (apply 'concat "Participants:\n" (format "%-15s %-15s %-11s %s\n" "Nickname" "Role" "Affiliation" "JID") (mapcar (lambda (x) (let ((plist (cdr x))) (format "%-15s %-15s %-11s %s\n" (car x) (plist-get plist 'role) (plist-get plist 'affiliation) (or (plist-get plist 'jid) "")))) participants))) (add-to-list 'jabber-jid-muc-menu (cons "Set topic" 'jabber-muc-set-topic)) (defun jabber-muc-set-topic (jc group topic) "Set topic of GROUP to TOPIC." (interactive (jabber-muc-argument-list (list (jabber-read-with-input-method "New topic: " jabber-muc-topic)))) (jabber-send-message jc group topic nil "groupchat")) (defun jabber-muc-snarf-topic (xml-data) "Record subject (topic) of the given , if any." (let ((new-topic (jabber-xml-path xml-data '(subject "")))) (when new-topic (setq jabber-muc-topic new-topic)))) (add-to-list 'jabber-jid-muc-menu (cons "Set role (kick, voice, op)" 'jabber-muc-set-role)) (defun jabber-muc-set-role (jc group nickname role reason) "Set role of NICKNAME in GROUP to ROLE, specifying REASON." (interactive (jabber-muc-argument-list (let ((nickname (jabber-muc-read-nickname jabber-group "Nickname: "))) (list nickname (completing-read "New role: " '(("none") ("visitor") ("participant") ("moderator")) nil t nil 'jabber-role-history) (read-string "Reason: "))))) (unless (or (zerop (length nickname)) (zerop (length role))) (jabber-send-iq jc group "set" `(query ((xmlns . "http://jabber.org/protocol/muc#admin")) (item ((nick . ,nickname) (role . ,role)) ,(unless (zerop (length reason)) `(reason () ,reason)))) 'jabber-report-success "Role change" 'jabber-report-success "Role change"))) (add-to-list 'jabber-jid-muc-menu (cons "Set affiliation (ban, member, admin)" 'jabber-muc-set-affiliation)) (defun jabber-muc-set-affiliation (jc group nickname-or-jid nickname-p affiliation reason) "Set affiliation of NICKNAME-OR-JID in GROUP to AFFILIATION. If NICKNAME-P is non-nil, NICKNAME-OR-JID is a nickname in the group, else it is a JID." (interactive (jabber-muc-argument-list (let ((nickname-p (y-or-n-p "Specify user by room nickname? "))) (list (if nickname-p (jabber-muc-read-nickname jabber-group "Nickname: ") (jabber-read-jid-completing "User: ")) nickname-p (completing-read "New affiliation: " '(("none") ("outcast") ("member") ("admin") ("owner")) nil t nil 'jabber-affiliation-history) (read-string "Reason: "))))) (let ((jid (if nickname-p (let ((participants (cdr (assoc group jabber-muc-participants)))) (unless participants (error "Couldn't find group %s" group)) (let ((participant (cdr (assoc nickname-or-jid participants)))) (unless participant (error "Couldn't find %s in group %s" nickname-or-jid group)) (or (plist-get participant 'jid) (error "JID of %s in group %s is unknown" nickname-or-jid group)))) nickname-or-jid))) (jabber-send-iq jc group "set" `(query ((xmlns . "http://jabber.org/protocol/muc#admin")) (item ((jid . ,jid) (affiliation . ,affiliation)) ,(unless (zerop (length reason)) `(reason () ,reason)))) 'jabber-report-success "Affiliation change" 'jabber-report-success "Affiliation change"))) (add-to-list 'jabber-jid-muc-menu (cons "Invite someone to chatroom" 'jabber-muc-invite)) (defun jabber-muc-invite (jc jid group reason) "Invite JID to GROUP, stating REASON." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Invite whom: " ;; The current room is _not_ a good default for whom to invite. (remq (jabber-jid-symbol jabber-group) (jabber-concat-rosters))) (jabber-muc-read-completing "To group: ") (jabber-read-with-input-method "Reason: "))) (jabber-send-sexp jc `(message ((to . ,group)) (x ((xmlns . "http://jabber.org/protocol/muc#user")) (invite ((to . ,jid)) ,(unless (zerop (length reason)) `(reason nil ,reason))))))) (add-to-list 'jabber-body-printers 'jabber-muc-print-invite) (defun jabber-muc-print-invite (xml-data who mode) "Print MUC invitation" (dolist (x (jabber-xml-get-children xml-data 'x)) (when (string= (jabber-xml-get-attribute x 'xmlns) "http://jabber.org/protocol/muc#user") (let ((invitation (car (jabber-xml-get-children x 'invite)))) (when invitation (when (eql mode :insert) (let ((group (jabber-xml-get-attribute xml-data 'from)) (inviter (jabber-xml-get-attribute invitation 'from)) (reason (car (jabber-xml-node-children (car (jabber-xml-get-children invitation 'reason)))))) ;; XXX: password (insert "You have been invited to MUC room " (jabber-jid-displayname group)) (when inviter (insert " by " (jabber-jid-displayname inviter))) (insert ".") (when reason (insert " Reason: " reason)) (insert "\n\n") (let ((action `(lambda (&rest ignore) (interactive) (jabber-groupchat-join jabber-buffer-connection ,group (jabber-muc-read-my-nickname jabber-buffer-connection ,group))))) (if (fboundp 'insert-button) (insert-button "Accept" 'action action) ;; Simple button replacement (let ((keymap (make-keymap))) (define-key keymap "\r" action) (insert (jabber-propertize "Accept" 'keymap keymap 'face 'highlight)))) (insert "\t") (let ((action `(lambda (&rest ignore) (interactive) (let ((reason (jabber-read-with-input-method "Reason: "))) (jabber-send-sexp jabber-buffer-connection (list 'message (list (cons 'to ,group)) (list 'x (list (cons 'xmlns "http://jabber.org/protocol/muc#user")) (list 'decline (list (cons 'to ,inviter)) (unless (zerop (length reason)) (list 'reason nil reason)))))))))) (if (fboundp 'insert-button) (insert-button "Decline" 'action action) ;; Simple button replacement (let ((keymap (make-keymap))) (define-key keymap "\r" action) (insert (jabber-propertize "Decline" 'keymap keymap 'face 'highlight)))))))) (return t)))))) (defun jabber-muc-autojoin (jc) "Join rooms specified in account bookmarks and global `jabber-muc-autojoin'." (interactive (list (jabber-read-account))) (let ((nickname (plist-get (fsm-get-state-data jc) :username))) (when (bound-and-true-p jabber-muc-autojoin) (dolist (group jabber-muc-autojoin) (jabber-groupchat-join jc group (or (cdr (assoc group jabber-muc-default-nicknames)) (plist-get (fsm-get-state-data jc) :username))))) (jabber-get-bookmarks jc (lambda (jc bookmarks) (dolist (bookmark bookmarks) (setq bookmark (jabber-parse-conference-bookmark bookmark)) (when (and bookmark (plist-get bookmark :autojoin)) (jabber-groupchat-join jc (plist-get bookmark :jid) (or (plist-get bookmark :nick) (plist-get (fsm-get-state-data jc) :username))))))))) ;;;###autoload (defun jabber-muc-message-p (message) "Return non-nil if MESSAGE is a groupchat message. That does not include private messages in a groupchat, but does include groupchat invites." ;; Public groupchat messages have type "groupchat" and are from ;; room@server/nick. Public groupchat errors have type "error" and ;; are from room@server. (let ((from (jabber-xml-get-attribute message 'from)) (type (jabber-xml-get-attribute message 'type))) (or (string= type "groupchat") (and (string= type "error") (gethash (jabber-jid-symbol from) jabber-pending-groupchats)) (jabber-xml-path message '(("http://jabber.org/protocol/muc#user" . "x") invite))))) ;;;###autoload (defun jabber-muc-sender-p (jid) "Return non-nil if JID is a full JID of an MUC participant." (and (assoc (jabber-jid-user jid) *jabber-active-groupchats*) (jabber-jid-resource jid))) ;;;###autoload (defun jabber-muc-private-message-p (message) "Return non-nil if MESSAGE is a private message in a groupchat." (let ((from (jabber-xml-get-attribute message 'from)) (type (jabber-xml-get-attribute message 'type))) (and (not (string= type "groupchat")) (jabber-muc-sender-p from)))) (add-to-list 'jabber-jid-muc-menu (cons "Open private chat" 'jabber-muc-private)) (defun jabber-muc-private (jc group nickname) "Open private chat with NICKNAME in GROUP." (interactive (jabber-muc-argument-list (list (jabber-muc-read-nickname jabber-group "Nickname: ")))) (switch-to-buffer (jabber-muc-private-create-buffer jabber-buffer-connection group nickname))) (defun jabber-muc-presence-p (presence) "Return non-nil if PRESENCE is presence from groupchat." (let ((from (jabber-xml-get-attribute presence 'from)) (type (jabber-xml-get-attribute presence 'type)) (muc-marker (find-if (lambda (x) (equal (jabber-xml-get-attribute x 'xmlns) "http://jabber.org/protocol/muc#user")) (jabber-xml-get-children presence 'x)))) ;; This is MUC presence if it has an MUC-namespaced tag... (or muc-marker ;; ...or if it is error presence from a room we tried to join. (and (string= type "error") (gethash (jabber-jid-symbol from) jabber-pending-groupchats))))) (defun jabber-muc-parse-affiliation (x-muc) "Parse X-MUC in the muc#user namespace and return a plist. Return nil if X-MUC is nil." ;; XXX: parse and tags? or maybe elsewhere? (apply 'nconc (mapcar (lambda (prop) (list (car prop) (cdr prop))) (jabber-xml-node-attributes (car (jabber-xml-get-children x-muc 'item)))))) (defun jabber-muc-print-prompt (xml-data &optional local dont-print-nick-p) "Print MUC prompt for message in XML-DATA." (let ((nick (jabber-jid-resource (jabber-xml-get-attribute xml-data 'from))) (timestamp (car (delq nil (mapcar 'jabber-x-delay (jabber-xml-get-children xml-data 'x)))))) (if (stringp nick) (insert (jabber-propertize (format-spec jabber-groupchat-prompt-format (list (cons ?t (format-time-string (if timestamp jabber-chat-delayed-time-format jabber-chat-time-format) timestamp)) (cons ?n (if dont-print-nick-p "" nick)) (cons ?u nick) (cons ?r nick) (cons ?j (concat jabber-group "/" nick)))) 'face (if local 'jabber-chat-prompt-local 'jabber-chat-prompt-foreign) 'help-echo (concat (format-time-string "On %Y-%m-%d %H:%M:%S" timestamp) " from " nick " in " jabber-group))) (jabber-muc-system-prompt)))) (defun jabber-muc-private-print-prompt (xml-data) "Print prompt for private MUC message in XML-DATA." (let ((nick (jabber-jid-resource (jabber-xml-get-attribute xml-data 'from))) (group (jabber-jid-user (jabber-xml-get-attribute xml-data 'from))) (timestamp (car (delq nil (mapcar 'jabber-x-delay (jabber-xml-get-children xml-data 'x)))))) (insert (jabber-propertize (format-spec jabber-muc-private-foreign-prompt-format (list (cons ?t (format-time-string (if timestamp jabber-chat-delayed-time-format jabber-chat-time-format) timestamp)) (cons ?n nick) (cons ?g (or (jabber-jid-rostername group) (jabber-jid-username group))))) 'face 'jabber-chat-prompt-foreign 'help-echo (concat (format-time-string "On %Y-%m-%d %H:%M:%S" timestamp) " from " nick " in " jabber-group))))) (defun jabber-muc-system-prompt (&rest ignore) "Print system prompt for MUC." (insert (jabber-propertize (format-spec jabber-groupchat-prompt-format (list (cons ?t (format-time-string jabber-chat-time-format)) (cons ?n "") (cons ?u "") (cons ?r "") (cons ?j jabber-group))) 'face 'jabber-chat-prompt-system 'help-echo (format-time-string "System message on %Y-%m-%d %H:%M:%S")))) (add-to-list 'jabber-message-chain 'jabber-muc-process-message) (defun jabber-muc-process-message (jc xml-data) "If XML-DATA is a groupchat message, handle it as such." (when (jabber-muc-message-p xml-data) (let* ((from (jabber-xml-get-attribute xml-data 'from)) (group (jabber-jid-user from)) (nick (jabber-jid-resource from)) (error-p (jabber-xml-get-children xml-data 'error)) (type (cond (error-p :muc-error) ((string= nick (cdr (assoc group *jabber-active-groupchats*))) :muc-local) (t :muc-foreign))) (body-text (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'body))))) (printers (append jabber-muc-printers jabber-chat-printers))) (with-current-buffer (jabber-muc-create-buffer jc group) (jabber-muc-snarf-topic xml-data) ;; Call alert hooks only when something is output (when (or error-p (run-hook-with-args-until-success 'printers xml-data type :printp)) (jabber-maybe-print-rare-time (ewoc-enter-last jabber-chat-ewoc (list type xml-data :time (current-time)))) ;; ...except if the message is part of history, in which ;; case we don't want an alert. (let ((children-namespaces (mapcar (lambda (x) (when (listp x) (jabber-xml-get-attribute x 'xmlns))) (jabber-xml-node-children xml-data)))) (unless (or (member "urn:xmpp:delay" children-namespaces) (member "jabber:x:delay" children-namespaces)) (dolist (hook '(jabber-muc-hooks jabber-alert-muc-hooks)) (run-hook-with-args hook nick group (current-buffer) body-text (funcall jabber-alert-muc-function nick group (current-buffer) body-text)))))))))) (defun jabber-muc-process-presence (jc presence) (let* ((from (jabber-xml-get-attribute presence 'from)) (type (jabber-xml-get-attribute presence 'type)) (x-muc (find-if (lambda (x) (equal (jabber-xml-get-attribute x 'xmlns) "http://jabber.org/protocol/muc#user")) (jabber-xml-get-children presence 'x))) (group (jabber-jid-user from)) (nickname (jabber-jid-resource from)) (symbol (jabber-jid-symbol from)) (item (car (jabber-xml-get-children x-muc 'item))) (actor (jabber-xml-get-attribute (car (jabber-xml-get-children item 'actor)) 'jid)) (reason (car (jabber-xml-node-children (car (jabber-xml-get-children item 'reason))))) (error-node (car (jabber-xml-get-children presence 'error))) (status-code (if error-node (jabber-xml-get-attribute error-node 'code) (jabber-xml-get-attribute (car (jabber-xml-get-children x-muc 'status)) 'code)))) ;; handle leaving a room (cond ((or (string= type "unavailable") (string= type "error")) ;; error from room itself? or are we leaving? (if (or (null nickname) (string= nickname (gethash (jabber-jid-symbol group) jabber-pending-groupchats))) ;; Assume that an error means that we were thrown out of the ;; room... (let* ((leavingp t) (message (cond ((string= type "error") (cond ;; ...except for certain cases. ((or (equal status-code "406") (equal status-code "409")) (setq leavingp nil) (concat "Nickname change not allowed" (when error-node (concat ": " (jabber-parse-error error-node))))) (t (concat "Error entering room" (when error-node (concat ": " (jabber-parse-error error-node))))))) ((equal status-code "301") (concat "You have been banned" (when actor (concat " by " actor)) (when reason (concat " - '" reason "'")))) ((equal status-code "307") (concat "You have been kicked" (when actor (concat " by " actor)) (when reason (concat " - '" reason "'")))) (t "You have left the chatroom")))) (when leavingp (jabber-muc-remove-groupchat group)) ;; If there is no buffer for this groupchat, don't bother ;; creating one just to tell that user left the room. (let ((buffer (get-buffer (jabber-muc-get-buffer group)))) (if buffer (with-current-buffer buffer (jabber-maybe-print-rare-time (ewoc-enter-last jabber-chat-ewoc (list (if (string= type "error") :muc-error :muc-notice) message :time (current-time))))) (message "%s: %s" (jabber-jid-displayname group) message)))) ;; or someone else? (let* ((plist (jabber-muc-participant-plist group nickname)) (jid (plist-get plist 'jid)) (name (concat nickname (when jid (concat " <" (jabber-jid-user jid) ">"))))) (jabber-muc-remove-participant group nickname) (with-current-buffer (jabber-muc-create-buffer jc group) (jabber-maybe-print-rare-time (ewoc-enter-last jabber-chat-ewoc (list :muc-notice (cond ((equal status-code "301") (concat name " has been banned" (when actor (concat " by " actor)) (when reason (concat " - '" reason "'")))) ((equal status-code "307") (concat name " has been kicked" (when actor (concat " by " actor)) (when reason (concat " - '" reason "'")))) ((equal status-code "303") (concat name " changes nickname to " (jabber-xml-get-attribute item 'nick))) (t (concat name " has left the chatroom"))) :time (current-time)))))))) (t ;; someone is entering (when (string= nickname (gethash (jabber-jid-symbol group) jabber-pending-groupchats)) ;; Our own nick? We just succeeded in entering the room. (let ((whichgroup (assoc group *jabber-active-groupchats*))) (if whichgroup (setcdr whichgroup nickname) (add-to-list '*jabber-active-groupchats* (cons group nickname))))) ;; Whoever enters, we create a buffer (if it didn't already ;; exist), and print a notice. This is where autojoined MUC ;; rooms have buffers created for them. We also remember some ;; metadata. (let ((old-plist (jabber-muc-participant-plist group nickname)) (new-plist (jabber-muc-parse-affiliation x-muc))) (jabber-muc-modify-participant group nickname new-plist) (let ((report (jabber-muc-report-delta nickname old-plist new-plist reason actor))) (when report (with-current-buffer (jabber-muc-create-buffer jc group) (jabber-maybe-print-rare-time (ewoc-enter-last jabber-chat-ewoc (list :muc-notice report :time (current-time)))))))))))) (provide 'jabber-muc) ;;; arch-tag: 1ff7ab35-1717-46ae-b803-6f5b3fb2cd7d emacs-jabber-0.8.0/jabber-newdisco.el0000644000175100017510000001451411133727374014352 00000000000000;;; jabber-newdisco.el --- caching disco API ;; Copyright (C) 2005, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;--- ;; Keys are ("jid" . "node"), where "node" is nil if appropriate. ;; Values are (identities features), where each identity is ["name" ;; "category" "type"], and each feature is a string. (defvar jabber-disco-info-cache (make-hash-table :test 'equal)) ;; Keys are ("jid" . "node"). Values are (items), where each ;; item is ["name" "jid" "node"] (some values may be nil). (defvar jabber-disco-items-cache (make-hash-table :test 'equal)) ;;; Info (defun jabber-disco-get-info (jc jid node callback closure-data &optional force) "Get disco info for JID and NODE, using connection JC. Call CALLBACK with JC and CLOSURE-DATA as first and second arguments and result as third argument when result is available. On success, result is (IDENTITIES FEATURES), where each identity is [\"name\" \"category\" \"type\"], and each feature is a string. On error, result is the error node, recognizable by (eq (car result) 'error). If CALLBACK is nil, just fetch data. If FORCE is non-nil, invalidate cache and get fresh data." (when force (remhash (cons jid node) jabber-disco-info-cache)) (let ((result (gethash (cons jid node) jabber-disco-info-cache))) (if result (and callback (run-with-timer 0 nil callback jc closure-data result)) (jabber-send-iq jc jid "get" `(query ((xmlns . "http://jabber.org/protocol/disco#info") ,(when node `(node . ,node)))) #'jabber-disco-got-info (cons callback closure-data) (lambda (jc xml-data callback-data) (when (car callback-data) (funcall (car callback-data) jc (cdr callback-data) (jabber-iq-error xml-data)))) (cons callback closure-data))))) (defun jabber-disco-got-info (jc xml-data callback-data) (let ((jid (jabber-xml-get-attribute xml-data 'from)) (node (jabber-xml-get-attribute (jabber-iq-query xml-data) 'node)) (result (list (mapcar #'(lambda (id) (vector (jabber-xml-get-attribute id 'name) (jabber-xml-get-attribute id 'category) (jabber-xml-get-attribute id 'type))) (jabber-xml-get-children (jabber-iq-query xml-data) 'identity)) (mapcar #'(lambda (feature) (jabber-xml-get-attribute feature 'var)) (jabber-xml-get-children (jabber-iq-query xml-data) 'feature))))) (puthash (cons jid node) result jabber-disco-info-cache) (when (car callback-data) (funcall (car callback-data) jc (cdr callback-data) result)))) (defun jabber-disco-get-info-immediately (jid node) "Get cached disco info for JID and NODE. Return nil if no info available. Fill the cache with `jabber-disco-get-info'." (gethash (cons jid node) jabber-disco-info-cache)) ;;; Items (defun jabber-disco-get-items (jc jid node callback closure-data &optional force) "Get disco items for JID and NODE, using connection JC. Call CALLBACK with JC and CLOSURE-DATA as first and second arguments and items result as third argument when result is available. On success, result is a list of items, where each item is [\"name\" \"jid\" \"node\"] (some values may be nil). On error, result is the error node, recognizable by (eq (car result) 'error). If CALLBACK is nil, just fetch data. If FORCE is non-nil, invalidate cache and get fresh data." (when force (remhash (cons jid node) jabber-disco-items-cache)) (let ((result (gethash (cons jid node) jabber-disco-items-cache))) (if result (and callback (run-with-timer 0 nil callback jc closure-data result)) (jabber-send-iq jc jid "get" `(query ((xmlns . "http://jabber.org/protocol/disco#items") ,(when node `(node . ,node)))) #'jabber-disco-got-items (cons callback closure-data) (lambda (jc xml-data callback-data) (when (car callback-data) (funcall (car callback-data) jc (cdr callback-data) (jabber-iq-error xml-data)))) (cons callback closure-data))))) (defun jabber-disco-got-items (jc xml-data callback-data) (let ((jid (jabber-xml-get-attribute xml-data 'from)) (node (jabber-xml-get-attribute (jabber-iq-query xml-data) 'node)) (result (mapcar #'(lambda (item) (vector (jabber-xml-get-attribute item 'name) (jabber-xml-get-attribute item 'jid) (jabber-xml-get-attribute item 'node))) (jabber-xml-get-children (jabber-iq-query xml-data) 'item)))) (puthash (cons jid node) result jabber-disco-items-cache) (when (car callback-data) (funcall (car callback-data) jc (cdr callback-data) result)))) (defun jabber-disco-get-items-immediately (jid node) (gethash (cons jid node) jabber-disco-items-cache)) ;;; Publish (defun jabber-disco-publish (jc node item-name item-jid item-node) "Publish the given item under disco node NODE." (jabber-send-iq jc nil "set" `(query ((xmlns . "http://jabber.org/protocol/disco#items") ,(when node `(node . ,node))) (item ((action . "update") (jid . ,item-jid) ,(when item-name `(name . ,item-name)) ,(when item-node `(node . ,item-node))))) 'jabber-report-success "Disco publish" 'jabber-report-success "Disco publish")) (defun jabber-disco-publish-remove (jc node item-jid item-node) "Remove the given item from published disco items." (jabber-send-iq jc nil "set" `(query ((xmlns . "http://jabber.org/protocol/disco#items") ,(when node `(node . ,node))) (item ((action . "remove") (jid . ,item-jid) ,(when item-node `(node . ,item-node))))) 'jabber-report-success "Disco removal" 'jabber-report-success "Disco removal")) (provide 'jabber-newdisco) ;; arch-tag: b47c06aa-cae6-11d9-b1c0-000a95c2fcd0 emacs-jabber-0.8.0/jabber-osd.el0000644000175100017510000000234411133727374013322 00000000000000;;; jabber-osd.el --- OSD support for jabber.el ;; Copyright (C) 2008 - Terechkov Evgenii - evg@altlinux.org ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. (eval-when-compile (require 'jabber-alert)) (condition-case e (progn ;; Most people don't have osd.el, so this will often fail (require 'osd) (define-jabber-alert osd "Display a message in osd" 'osd-show-string) (define-personal-jabber-alert jabber-muc-osd) ) (error nil)) (provide 'jabber-osd) ;; arch-tag: 3eb8d55a-dd86-11dc-b2c6-000a95c2fcd0 emacs-jabber-0.8.0/jabber-presence.el0000644000175100017510000005047211250455045014337 00000000000000;; jabber-presence.el - roster and presence bookkeeping ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-core) (require 'jabber-iq) (require 'jabber-alert) (require 'jabber-util) (require 'jabber-menu) (require 'jabber-muc) (require 'jabber-autoloads) (require 'assoc) (defvar jabber-presence-element-functions nil "List of functions returning extra elements for stanzas. Each function takes one argument, the connection, and returns a possibly empty list of extra child element of the stanza.") (defvar jabber-presence-history () "Keeps track of previously used presence status types") (add-to-list 'jabber-iq-set-xmlns-alist (cons "jabber:iq:roster" (function (lambda (jc x) (jabber-process-roster jc x nil))))) (defun jabber-process-roster (jc xml-data closure-data) "process an incoming roster infoquery result CLOSURE-DATA should be 'initial if initial roster push, nil otherwise." (let ((roster (plist-get (fsm-get-state-data jc) :roster)) (from (jabber-xml-get-attribute xml-data 'from)) (type (jabber-xml-get-attribute xml-data 'type)) (id (jabber-xml-get-attribute xml-data 'id)) (username (plist-get (fsm-get-state-data jc) :username)) (server (plist-get (fsm-get-state-data jc) :server)) (resource (plist-get (fsm-get-state-data jc) :resource)) new-items changed-items deleted-items) ;; Perform sanity check on "from" attribute: it should be either absent ;; or match our own JID. (if (not (or (null from) (string= from (concat username "@" server)) (string= from (concat username "@" server "/" resource)))) (message "Roster push with invalid \"from\": \"%s\" (expected \"%s@%s\" or \"%s@%s/%s\")" from username server username server resource) (dolist (item (jabber-xml-get-children (car (jabber-xml-get-children xml-data 'query)) 'item)) (let (roster-item (jid (jabber-jid-symbol (jabber-xml-get-attribute item 'jid)))) ;; If subscripton="remove", contact is to be removed from roster (if (string= (jabber-xml-get-attribute item 'subscription) "remove") (progn (message "%s removed from roster" jid) (push jid deleted-items)) ;; Find contact if already in roster (setq roster-item (car (memq jid roster))) (if roster-item (push roster-item changed-items) ;; If not found, create a new roster item. (message "%s added to roster" jid) (setq roster-item jid) (push roster-item new-items)) ;; If this is an initial push, we want to forget ;; everything we knew about this contact before - e.g. if ;; the contact was online when we disconnected and offline ;; when we reconnect, we don't want to see stale presence ;; information. This assumes that no contacts are shared ;; between accounts. (when (eq closure-data 'initial) (setplist roster-item nil)) ;; Now, get all data associated with the contact. (put roster-item 'name (jabber-xml-get-attribute item 'name)) (put roster-item 'subscription (jabber-xml-get-attribute item 'subscription)) (put roster-item 'ask (jabber-xml-get-attribute item 'ask)) ;; Since roster items can't be changed incrementally, we ;; save the original XML to be able to modify it, instead of ;; having to reproduce it. This is for forwards ;; compatibility. (put roster-item 'xml item) (put roster-item 'groups (mapcar (lambda (foo) (nth 2 foo)) (jabber-xml-get-children item 'group))))))) ;; This is the function that does the actual updating and ;; redrawing of the roster. (jabber-roster-update jc new-items changed-items deleted-items) (if (and id (string= type "set")) (jabber-send-iq jc nil "result" nil nil nil nil nil id))) ;; After initial roster push, run jabber-post-connect-hooks. We do ;; it here and not before since we want to have the entire roster ;; before we receive any presence stanzas. (when (eq closure-data 'initial) (run-hook-with-args 'jabber-post-connect-hooks jc))) (add-to-list 'jabber-presence-chain 'jabber-process-presence) (defun jabber-process-presence (jc xml-data) "process incoming presence tags" ;; XXX: use JC argument (let ((roster (plist-get (fsm-get-state-data jc) :roster)) (from (jabber-xml-get-attribute xml-data 'from)) (to (jabber-xml-get-attribute xml-data 'to)) (type (jabber-xml-get-attribute xml-data 'type)) (presence-show (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'show))))) (presence-status (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'status))))) (error (car (jabber-xml-get-children xml-data 'error))) (priority (string-to-number (or (car (jabber-xml-node-children (car (jabber-xml-get-children xml-data 'priority)))) "0")))) (cond ((string= type "subscribe") (run-with-idle-timer 0.01 nil #'jabber-process-subscription-request jc from presence-status)) ((jabber-muc-presence-p xml-data) (jabber-muc-process-presence jc xml-data)) (t ;; XXX: Think about what to do about out-of-roster presences. (let ((buddy (jabber-jid-symbol from))) (if (memq buddy roster) (let* ((oldstatus (get buddy 'show)) (resource (or (jabber-jid-resource from) "")) (resource-plist (cdr (assoc resource (get buddy 'resources)))) newstatus) (cond ((and (string= resource "") (member type '("unavailable" "error"))) ;; 'unavailable' or 'error' from bare JID means that all resources ;; are offline. (setq resource-plist nil) (setq newstatus (if (string= type "error") "error" nil)) (let ((new-message (if error (jabber-parse-error error) presence-status))) ;; erase any previous information (put buddy 'resources nil) (put buddy 'connected nil) (put buddy 'show newstatus) (put buddy 'status new-message))) ((string= type "unavailable") (setq resource-plist (plist-put resource-plist 'connected nil)) (setq resource-plist (plist-put resource-plist 'show nil)) (setq resource-plist (plist-put resource-plist 'status presence-status))) ((string= type "error") (setq newstatus "error") (setq resource-plist (plist-put resource-plist 'connected nil)) (setq resource-plist (plist-put resource-plist 'show "error")) (setq resource-plist (plist-put resource-plist 'status (if error (jabber-parse-error error) presence-status)))) ((or (string= type "unsubscribe") (string= type "subscribed") (string= type "unsubscribed")) ;; Do nothing, except letting the user know. The Jabber protocol ;; places all this complexity on the server. (setq newstatus type)) (t (setq resource-plist (plist-put resource-plist 'connected t)) (setq resource-plist (plist-put resource-plist 'show (or presence-show ""))) (setq resource-plist (plist-put resource-plist 'status presence-status)) (setq resource-plist (plist-put resource-plist 'priority priority)) (setq newstatus (or presence-show "")))) (when resource-plist ;; this is for `assoc-set!' in guile (if (assoc resource (get buddy 'resources)) (setcdr (assoc resource (get buddy 'resources)) resource-plist) (put buddy 'resources (cons (cons resource resource-plist) (get buddy 'resources)))) (jabber-prioritize-resources buddy)) (fsm-send jc (cons :roster-update buddy)) (dolist (hook '(jabber-presence-hooks jabber-alert-presence-hooks)) (run-hook-with-args hook buddy oldstatus newstatus (plist-get resource-plist 'status) (funcall jabber-alert-presence-message-function buddy oldstatus newstatus (plist-get resource-plist 'status))))))))))) (defun jabber-process-subscription-request (jc from presence-status) "process an incoming subscription request" (with-current-buffer (jabber-chat-create-buffer jc from) (ewoc-enter-last jabber-chat-ewoc (list :subscription-request presence-status :time (current-time))) (dolist (hook '(jabber-presence-hooks jabber-alert-presence-hooks)) (run-hook-with-args hook (jabber-jid-symbol from) nil "subscribe" presence-status (funcall jabber-alert-presence-message-function (jabber-jid-symbol from) nil "subscribe" presence-status))))) (defun jabber-subscription-accept-mutual (&rest ignored) (message "Subscription accepted; reciprocal subscription request sent") (jabber-subscription-reply "subscribed" "subscribe")) (defun jabber-subscription-accept-one-way (&rest ignored) (message "Subscription accepted") (jabber-subscription-reply "subscribed")) (defun jabber-subscription-decline (&rest ignored) (message "Subscription declined") (jabber-subscription-reply "unsubscribed")) (defun jabber-subscription-reply (&rest types) (let ((to (jabber-jid-user jabber-chatting-with))) (dolist (type types) (jabber-send-sexp jabber-buffer-connection `(presence ((to . ,to) (type . ,type))))))) (defun jabber-prioritize-resources (buddy) "Set connected, show and status properties for BUDDY from highest-priority resource." (let ((resource-alist (get buddy 'resources)) (highest-priority nil)) ;; Reset to nil at first, for cases (a) resource-alist is nil ;; and (b) all resources are disconnected. (put buddy 'connected nil) (put buddy 'show nil) (put buddy 'status nil) (mapc #'(lambda (resource) (let* ((resource-plist (cdr resource)) (priority (plist-get resource-plist 'priority))) (if (plist-get resource-plist 'connected) (when (or (null highest-priority) (and priority (> priority highest-priority))) ;; if no priority specified, interpret as zero (setq highest-priority (or priority 0)) (put buddy 'connected (plist-get resource-plist 'connected)) (put buddy 'show (plist-get resource-plist 'show)) (put buddy 'status (plist-get resource-plist 'status)) (put buddy 'resource (car resource))) ;; if we have not found a connected resource yet, but this ;; disconnected resource has a status message, display it. (when (not (get buddy 'connected)) (if (plist-get resource-plist 'status) (put buddy 'status (plist-get resource-plist 'status))) (if (plist-get resource-plist 'show) (put buddy 'show (plist-get resource-plist 'show))))))) resource-alist))) (defun jabber-count-connected-resources (buddy) "Return the number of connected resources for BUDDY." (let ((resource-alist (get buddy 'resources)) (count 0)) (dolist (resource resource-alist) (if (plist-get (cdr resource) 'connected) (setq count (1+ count)))) count)) ;;;###autoload (defun jabber-send-presence (show status priority) "Set presence for all accounts." (interactive (list (completing-read "show: " '("" "away" "xa" "dnd" "chat") nil t nil 'jabber-presence-history) (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*) (read-string "priority: " (int-to-string (if *jabber-current-priority* *jabber-current-priority* jabber-default-priority))))) (setq *jabber-current-show* show *jabber-current-status* status) (setq *jabber-current-priority* (if (numberp priority) priority (string-to-number priority))) (let (subelements-map) ;; For each connection, we use a different set of subelements. We ;; cache them, to only generate them once. ;; Ordinary presence, with no specified recipient (dolist (jc jabber-connections) (let ((subelements (jabber-presence-children jc))) (aput 'subelements-map jc subelements) (jabber-send-sexp-if-connected jc `(presence () ,@subelements)))) ;; Then send presence to groupchats (dolist (gc *jabber-active-groupchats*) (let* ((buffer (get-buffer (jabber-muc-get-buffer (car gc)))) (jc (when buffer (buffer-local-value 'jabber-buffer-connection buffer))) (subelements (cdr (assq jc subelements-map)))) (when jc (jabber-send-sexp-if-connected jc `(presence ((to . ,(car gc))) ,@subelements)))))) (jabber-display-roster)) (defun jabber-presence-children (jc) "Return the children for a stanza." `(,(when (> (length *jabber-current-status*) 0) `(status () ,*jabber-current-status*)) ,(when (> (length *jabber-current-show*) 0) `(show () ,*jabber-current-show*)) ,(when *jabber-current-priority* `(priority () ,(number-to-string *jabber-current-priority*))) ,@(apply 'append (mapcar (lambda (f) (funcall f jc)) jabber-presence-element-functions)))) (defun jabber-send-directed-presence (jc jid type) "Send a directed presence stanza to JID. TYPE is one of: \"online\", \"away\", \"xa\", \"dnd\", \"chatty\": Appear as present with the given status. \"unavailable\": Appear as offline. \"probe\": Ask the contact's server for updated presence. \"subscribe\": Ask for subscription to contact's presence. (see also `jabber-send-subscription-request') \"unsubscribe\": Cancel your subscription to contact's presence. \"subscribed\": Accept contact's request for presence subscription. (this is usually done within a chat buffer) \"unsubscribed\": Cancel contact's subscription to your presence." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Send directed presence to: ") (completing-read "Type (default is online): " '(("online") ("away") ("xa") ("dnd") ("chatty") ("probe") ("unavailable") ("subscribe") ("unsubscribe") ("subscribed") ("unsubscribed")) nil t nil 'jabber-presence-history "online"))) (cond ((member type '("probe" "unavailable" "subscribe" "unsubscribe" "subscribed" "unsubscribed")) (jabber-send-sexp jc `(presence ((to . ,jid) (type . ,type))))) (t (let ((*jabber-current-show* (if (string= type "online") "" type)) (*jabber-current-status* nil)) (jabber-send-sexp jc `(presence ((to . ,jid)) ,@(jabber-presence-children jc))))))) (defun jabber-send-away-presence (&optional status) "Set status to away. With prefix argument, ask for status message." (interactive (list (when current-prefix-arg (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*)))) (jabber-send-presence "away" (if status status *jabber-current-status*) *jabber-current-priority*)) ;; XXX code duplication! (defun jabber-send-xa-presence (&optional status) "Send extended away presence. With prefix argument, ask for status message." (interactive (list (when current-prefix-arg (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*)))) (jabber-send-presence "xa" (if status status *jabber-current-status*) *jabber-current-priority*)) ;;;###autoload (defun jabber-send-default-presence (&optional ignore) "Send default presence. Default presence is specified by `jabber-default-show', `jabber-default-status', and `jabber-default-priority'." (interactive) (jabber-send-presence jabber-default-show jabber-default-status jabber-default-priority)) (defun jabber-send-current-presence (&optional ignore) "(Re-)send current presence. That is, if presence has already been sent, use current settings, otherwise send defaults (see `jabber-send-default-presence')." (interactive) (if *jabber-current-show* (jabber-send-presence *jabber-current-show* *jabber-current-status* *jabber-current-priority*) (jabber-send-default-presence))) (add-to-list 'jabber-jid-roster-menu (cons "Send subscription request" 'jabber-send-subscription-request)) (defun jabber-send-subscription-request (jc to &optional request) "send a subscription request to jid, showing him your request text, if specified" (interactive (list (jabber-read-account) (jabber-read-jid-completing "to: ") (jabber-read-with-input-method "request: "))) (jabber-send-sexp jc `(presence ((to . ,to) (type . "subscribe")) ,@(when (and request (> (length request) 0)) (list `(status () ,request)))))) (defvar jabber-roster-group-history nil "History of entered roster groups") (add-to-list 'jabber-jid-roster-menu (cons "Add/modify roster entry" 'jabber-roster-change)) (defun jabber-roster-change (jc jid name groups) "Add or change a roster item." (interactive (let* ((jid (jabber-jid-symbol (jabber-read-jid-completing "Add/change JID: "))) (account (jabber-read-account)) (name (get jid 'name)) (groups (get jid 'groups)) (all-groups (apply #'append (mapcar (lambda (j) (get j 'groups)) (plist-get (fsm-get-state-data account) :roster))))) (when (string< emacs-version "22") ;; Older emacsen want the completion table to be an alist... (setq all-groups (mapcar #'list all-groups))) (list account jid (jabber-read-with-input-method (format "Name: (default `%s') " name) nil nil name) (delete "" (completing-read-multiple (format "Groups, comma-separated: (default %s) " (if groups (mapconcat #'identity groups ",") "none")) all-groups nil nil nil 'jabber-roster-group-history (mapconcat #'identity groups ",") t))))) ;; If new fields are added to the roster XML structure in a future standard, ;; they will be clobbered by this function. ;; XXX: specify account (jabber-send-iq jc nil "set" (list 'query (list (cons 'xmlns "jabber:iq:roster")) (list 'item (append (list (cons 'jid (symbol-name jid))) (if (and name (> (length name) 0)) (list (cons 'name name)))) (mapcar #'(lambda (x) `(group () ,x)) groups))) #'jabber-report-success "Roster item change" #'jabber-report-success "Roster item change")) (add-to-list 'jabber-jid-roster-menu (cons "Delete roster entry" 'jabber-roster-delete)) (defun jabber-roster-delete (jc jid) (interactive (list (jabber-read-account) (jabber-read-jid-completing "Delete from roster: "))) (jabber-send-iq jc nil "set" `(query ((xmlns . "jabber:iq:roster")) (item ((jid . ,jid) (subscription . "remove")))) #'jabber-report-success "Roster item removal" #'jabber-report-success "Roster item removal")) (defun jabber-roster-delete-jid-at-point () "Delete JID at point from roster. Signal an error if there is no JID at point." (interactive) (let ((jid-at-point (get-text-property (point) 'jabber-jid)) (account (get-text-property (point) 'jabber-account))) (if (and jid-at-point account (yes-or-no-p (format "Really delete %s from roster? " jid-at-point))) (jabber-roster-delete account jid-at-point) (error "No contact at point")))) (defun jabber-roster-delete-group-from-jids (jc jids group) "Delete group `group' from all JIDs" (interactive) (dolist (jid jids) (jabber-roster-change jc jid (get jid 'name) (remove-if-not (lambda (g) (not (string= g group))) (get jid 'groups))))) (defun jabber-roster-edit-group-from-jids (jc jids group) "Edit group `group' from all JIDs" (interactive) (let ((new-group (jabber-read-with-input-method (format "New group: (default `%s') " group) nil nil group))) (dolist (jid jids) (jabber-roster-change jc jid (get jid 'name) (remove-duplicates (mapcar (lambda (g) (if (string= g group) new-group g)) (get jid 'groups)) :test 'string=))))) (provide 'jabber-presence) ;;; arch-tag: b8616d4c-dde8-423e-86c7-da7b4928afc3 emacs-jabber-0.8.0/jabber-private.el0000644000175100017510000000426711133727374014215 00000000000000;;; jabber-private.el --- jabber:iq:private API by JEP-0049 ;; Copyright (C) 2005 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;;###autoload (defun jabber-private-get (jc node-name namespace success-callback error-callback) "Retrieve an item from private XML storage. The item to retrieve is identified by NODE-NAME (a symbol) and NAMESPACE (a string). On success, SUCCESS-CALLBACK is called with JC and the retrieved XML fragment. On error, ERROR-CALLBACK is called with JC and the entire IQ result." (jabber-send-iq jc nil "get" `(query ((xmlns . "jabber:iq:private")) (,node-name ((xmlns . ,namespace)))) #'jabber-private-get-1 success-callback #'(lambda (jc xml-data error-callback) (funcall error-callback jc xml-data)) error-callback)) (defun jabber-private-get-1 (jc xml-data success-callback) (funcall success-callback jc (car (jabber-xml-node-children (jabber-iq-query xml-data))))) ;;;###autoload (defun jabber-private-set (jc fragment &optional success-callback success-closure-data error-callback error-closure-data) "Store FRAGMENT in private XML storage. SUCCESS-CALLBACK, SUCCESS-CLOSURE-DATA, ERROR-CALLBACK and ERROR-CLOSURE-DATA are used as in `jabber-send-iq'." (jabber-send-iq jc nil "set" `(query ((xmlns . "jabber:iq:private")) ,fragment) success-callback success-closure-data error-callback error-closure-data)) (provide 'jabber-private) ;; arch-tag: 065bd03e-40fa-11da-ab48-000a95c2fcd0 emacs-jabber-0.8.0/jabber-ratpoison.el0000644000175100017510000000255111133727374014553 00000000000000;; jabber-ratpoison.el - emacs-jabber interface to ratpoison ;; Copyright (C) 2005, 2008 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'jabber-alert)) (defun jabber-ratpoison-message (msg) "Show MSG in Ratpoison" ;; Possible errors include not finding the ratpoison binary. (condition-case e (let ((process-connection-type)) (call-process "ratpoison" nil 0 nil "-c" (concat "echo " msg))) (error nil))) (define-jabber-alert ratpoison "Show a message through the Ratpoison window manager" 'jabber-ratpoison-message) (provide 'jabber-ratpoison) ;; arch-tag: 19650075-5D05-11D9-B80F-000A95C2FCD0 emacs-jabber-0.8.0/jabber-register.el0000644000175100017510000001242111133727374014356 00000000000000;; jabber-register.el - registration according to JEP-0077 ;; Copyright (C) 2003, 2004, 2007 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-iq) (require 'jabber-widget) (add-to-list 'jabber-jid-service-menu (cons "Register with service" 'jabber-get-register)) (defun jabber-get-register (jc to) "Send IQ get request in namespace \"jabber:iq:register\"." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Register with: "))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:register"))) #'jabber-process-data #'jabber-process-register-or-search #'jabber-report-success "Registration")) (defun jabber-process-register-or-search (jc xml-data) "Display results from jabber:iq:{register,search} query as a form." (let ((query (jabber-iq-query xml-data)) (have-xdata nil) (type (cond ((string= (jabber-iq-xmlns xml-data) "jabber:iq:register") 'register) ((string= (jabber-iq-xmlns xml-data) "jabber:iq:search") 'search) (t (error "Namespace %s not handled by jabber-process-register-or-search" (jabber-iq-xmlns xml-data))))) (register-account (plist-get (fsm-get-state-data jc) :registerp)) (username (plist-get (fsm-get-state-data jc) :username)) (server (plist-get (fsm-get-state-data jc) :server))) (cond ((eq type 'register) ;; If there is no `from' attribute, we are registering with the server (jabber-init-widget-buffer (or (jabber-xml-get-attribute xml-data 'from) server))) ((eq type 'search) ;; no such thing here (jabber-init-widget-buffer (jabber-xml-get-attribute xml-data 'from)))) (setq jabber-buffer-connection jc) (widget-insert (if (eq type 'register) "Register with " "Search ") jabber-submit-to "\n\n") (dolist (x (jabber-xml-get-children query 'x)) (when (string= (jabber-xml-get-attribute x 'xmlns) "jabber:x:data") (setq have-xdata t) ;; If the registration form obeys JEP-0068, we know ;; for sure how to put a default username in it. (jabber-render-xdata-form x (if (and register-account (string= (jabber-xdata-formtype x) "jabber:iq:register")) (list (cons "username" username)) nil)))) (if (not have-xdata) (jabber-render-register-form query (when register-account username))) (widget-create 'push-button :notify (if (eq type 'register) #'jabber-submit-register #'jabber-submit-search) "Submit") (when (eq type 'register) (widget-insert "\t") (widget-create 'push-button :notify #'jabber-remove-register "Cancel registration")) (widget-insert "\n") (widget-setup) (widget-minor-mode 1))) (defun jabber-submit-register (&rest ignore) "Submit registration input. See `jabber-process-register-or-search'." (let* ((registerp (plist-get (fsm-get-state-data jabber-buffer-connection) :registerp)) (handler (if registerp #'jabber-process-register-secondtime #'jabber-report-success)) (text (concat "Registration with " jabber-submit-to))) (jabber-send-iq jabber-buffer-connection jabber-submit-to "set" (cond ((eq jabber-form-type 'register) `(query ((xmlns . "jabber:iq:register")) ,@(jabber-parse-register-form))) ((eq jabber-form-type 'xdata) `(query ((xmlns . "jabber:iq:register")) ,(jabber-parse-xdata-form))) (t (error "Unknown form type: %s" jabber-form-type))) handler (if registerp 'success text) handler (if registerp 'failure text))) (message "Registration sent")) (defun jabber-process-register-secondtime (jc xml-data closure-data) "Receive registration success or failure. CLOSURE-DATA is either 'success or 'error." (cond ((eq closure-data 'success) (message "Registration successful. You may now connect to the server.")) (t (jabber-report-success jc xml-data "Account registration"))) (sit-for 3) (jabber-disconnect-one jc)) (defun jabber-remove-register (&rest ignore) "Cancel registration. See `jabber-process-register-or-search'." (if (yes-or-no-p (concat "Are you sure that you want to cancel your registration to " jabber-submit-to "? ")) (jabber-send-iq jabber-buffer-connection jabber-submit-to "set" '(query ((xmlns . "jabber:iq:register")) (remove)) #'jabber-report-success "Unregistration" #'jabber-report-success "Unregistration"))) (provide 'jabber-register) ;;; arch-tag: e6b349d6-b1ad-4d19-a412-74459dfae239 emacs-jabber-0.8.0/jabber-roster.el0000644000175100017510000006552711250455045014060 00000000000000;; jabber-roster.el - displaying the roster -*- coding: utf-8; -*- ;; Copyright (C) 2009 - Kirill A. Korinskiy - catap@catap.ru ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-presence) (require 'jabber-util) (require 'jabber-alert) (require 'jabber-keymap) (require 'format-spec) (defgroup jabber-roster nil "roster display options" :group 'jabber) (defcustom jabber-roster-line-format " %a %c %-25n %u %-8s %S" "The format specification of the lines in the roster display. These fields are available: %a Avatar, if any %c \"*\" if the contact is connected, or \" \" if not %u sUbscription state - see below %n Nickname of contact, or JID if no nickname %j Bare JID of contact (without resource) %r Highest-priority resource of contact %s Availability of contact as string (\"Online\", \"Away\" etc) %S Status string specified by contact %u is replaced by one of the strings given by `jabber-roster-subscription-display'." :type 'string :group 'jabber-roster) (defcustom jabber-roster-subscription-display '(("none" . " ") ("from" . "< ") ("to" . " >") ("both" . "<->")) "Strings used for indicating subscription status of contacts. \"none\" means that there is no subscription between you and the contact. \"from\" means that the contact has a subscription to you, but you have no subscription to the contact. \"to\" means that you have a subscription to the contact, but the contact has no subscription to you. \"both\" means a mutual subscription. Having a \"presence subscription\" means being able to see the other person's presence. Some fancy arrows you might want to use, if your system can display them: ← → ⇄ ↔" :type '(list (cons :format "%v" (const :format "" "none") (string :tag "None")) (cons :format "%v" (const :format "" "from") (string :tag "From")) (cons :format "%v" (const :format "" "to") (string :tag "To")) (cons :format "%v" (const :format "" "both") (string :tag "Both"))) :group 'jabber-roster) (defcustom jabber-resource-line-format " %r - %s (%S), priority %p" "The format specification of resource lines in the roster display. These are displayed when `jabber-show-resources' permits it. These fields are available: %c \"*\" if the contact is connected, or \" \" if not %n Nickname of contact, or JID if no nickname %j Bare JID of contact (without resource) %p Priority of this resource %r Name of this resource %s Availability of resource as string (\"Online\", \"Away\" etc) %S Status string specified by resource" :type 'string :group 'jabber-roster) (defcustom jabber-roster-sort-functions '(jabber-roster-sort-by-status jabber-roster-sort-by-displayname) "Sort roster according to these criteria. These functions should take two roster items A and B, and return: <0 if A < B 0 if A = B >0 if A > B" :type 'hook :options '(jabber-roster-sort-by-status jabber-roster-sort-by-displayname jabber-roster-sort-by-group) :group 'jabber-roster) (defcustom jabber-sort-order '("chat" "" "away" "dnd" "xa") "Sort by status in this order. Anything not in list goes last. Offline is represented as nil." :type '(repeat (restricted-sexp :match-alternatives (stringp nil))) :group 'jabber-roster) (defcustom jabber-show-resources 'sometimes "Show contacts' resources in roster? This can be one of the following symbols: nil Never show resources sometimes Show resources when there are more than one always Always show resources" :type '(radio (const :tag "Never" nil) (const :tag "When more than one connected resource" sometimes) (const :tag "Always" always)) :group 'jabber-roster) (defcustom jabber-show-offline-contacts t "Show offline contacts in roster when non-nil" :type 'boolean :group 'jabber-roster) (defcustom jabber-remove-newlines t "Remove newlines in status messages? Newlines in status messages mess up the roster display. However, they are essential to status message poets. Therefore, you get to choose the behaviour. Trailing newlines are always removed, regardless of this variable." :type 'boolean :group 'jabber-roster) (defcustom jabber-roster-show-bindings t "Show keybindings in roster buffer?" :type 'boolean :group 'jabber-roster) (defcustom jabber-roster-show-title t "Show title in roster buffer?" :type 'boolean :group 'jabber-roster) (defcustom jabber-roster-mode-hook nil "Hook run when entering Roster mode." :group 'jabber-roster :type 'hook) (defcustom jabber-roster-default-group-name "other" "Default group name for buddies without groups." :group 'jabber-roster :type 'string) (defcustom jabber-roster-show-empty-group nil "Show empty groups in roster?" :group 'jabber-roster :type 'boolean) (defcustom jabber-roster-roll-up-group nil "Show empty groups in roster?" :group 'jabber-roster :type 'boolean) (defface jabber-roster-user-online '((t (:foreground "blue" :weight bold :slant normal))) "face for displaying online users" :group 'jabber-roster) (defface jabber-roster-user-xa '((((background dark)) (:foreground "magenta" :weight normal :slant italic)) (t (:foreground "black" :weight normal :slant italic))) "face for displaying extended away users" :group 'jabber-roster) (defface jabber-roster-user-dnd '((t (:foreground "red" :weight normal :slant italic))) "face for displaying do not disturb users" :group 'jabber-roster) (defface jabber-roster-user-away '((t (:foreground "dark green" :weight normal :slant italic))) "face for displaying away users" :group 'jabber-roster) (defface jabber-roster-user-chatty '((t (:foreground "dark orange" :weight bold :slant normal))) "face for displaying chatty users" :group 'jabber-roster) (defface jabber-roster-user-error '((t (:foreground "red" :weight light :slant italic))) "face for displaying users sending presence errors" :group 'jabber-roster) (defface jabber-roster-user-offline '((t (:foreground "dark grey" :weight light :slant italic))) "face for displaying offline users" :group 'jabber-roster) (defvar jabber-roster-debug nil "debug roster draw") (defvar jabber-roster-mode-map (let ((map (make-sparse-keymap))) (suppress-keymap map) (set-keymap-parent map jabber-common-keymap) (define-key map [mouse-2] 'jabber-roster-mouse-2-action-at-point) (define-key map (kbd "TAB") 'jabber-go-to-next-jid) (define-key map (kbd "S-TAB") 'jabber-go-to-previous-jid) (define-key map (kbd "M-TAB") 'jabber-go-to-previous-jid) (define-key map (kbd "") 'jabber-go-to-previous-jid) (define-key map (kbd "RET") 'jabber-roster-ret-action-at-point) (define-key map (kbd "C-k") 'jabber-roster-delete-at-point) (define-key map "e" 'jabber-roster-edit-action-at-point) (define-key map "s" 'jabber-send-subscription-request) (define-key map "q" 'bury-buffer) (define-key map "i" 'jabber-get-disco-items) (define-key map "j" 'jabber-groupchat-join) (define-key map "I" 'jabber-get-disco-info) (define-key map "b" 'jabber-get-browse) (define-key map "v" 'jabber-get-version) (define-key map "a" 'jabber-send-presence) (define-key map "g" 'jabber-display-roster) (define-key map "S" 'jabber-ft-send) (define-key map "o" 'jabber-roster-toggle-offline-display) (define-key map "H" 'jabber-roster-toggle-binding-display) ;;(define-key map "D" 'jabber-disconnect) map)) (defun jabber-roster-ret-action-at-point () "Action for ret. Before try to roll up/down group. Eval chat-with-jid-at-point is no group at point" (interactive) (let ((group-at-point (get-text-property (point) 'jabber-group)) (account-at-point (get-text-property (point) 'jabber-account))) (if (and group-at-point account-at-point) (jabber-roster-roll-group account-at-point group-at-point) (jabber-chat-with-jid-at-point)))) (defun jabber-roster-mouse-2-action-at-point (e) "Action for mouse-2. Before try to roll up/down group. Eval chat-with-jid-at-point is no group at point" (interactive "e") (mouse-set-point e) (let ((group-at-point (get-text-property (point) 'jabber-group)) (account-at-point (get-text-property (point) 'jabber-account))) (if (and group-at-point account-at-point) (jabber-roster-roll-group account-at-point group-at-point) (jabber-popup-combined-menu)))) (defun jabber-roster-delete-at-point () "Delete at point from roster. Try to delete the group from all contaacs. Delete a jid if there is no group at point." (interactive) (let ((group-at-point (get-text-property (point) 'jabber-group)) (account-at-point (get-text-property (point) 'jabber-account))) (if (and group-at-point account-at-point) (let ((jids-with-group (gethash group-at-point (plist-get (fsm-get-state-data account-at-point) :roster-hash)))) (jabber-roster-delete-group-from-jids account-at-point jids-with-group group-at-point)) (jabber-roster-delete-jid-at-point)))) (defun jabber-roster-edit-action-at-point () "Action for e. Before try to edit group name. Eval `jabber-roster-change' is no group at point" (interactive) (let ((group-at-point (get-text-property (point) 'jabber-group)) (account-at-point (get-text-property (point) 'jabber-account))) (if (and group-at-point account-at-point) (let ((jids-with-group (gethash group-at-point (plist-get (fsm-get-state-data account-at-point) :roster-hash)))) (jabber-roster-edit-group-from-jids account-at-point jids-with-group group-at-point)) (call-interactively 'jabber-roster-change)))) (defun jabber-roster-roll-group (jc group-name) "Roll up/down group in roster" (let* ((state-data (fsm-get-state-data jc)) (roll-groups (plist-get state-data :roster-roll-groups))) (plist-put state-data :roster-roll-groups (if (find group-name roll-groups :test 'string=) (remove-if-not (lambda (group-name-in-list) (not (string= group-name group-name-in-list))) roll-groups) (append roll-groups (list group-name))))) (jabber-display-roster)) (defun jabber-roster-mode () "Major mode for Jabber roster display. Use the keybindings (mnemonic as Chat, Roster, Info, MUC, Service) to bring up menus of actions. \\{jabber-roster-mode-map}" (kill-all-local-variables) (setq major-mode 'jabber-roster-mode mode-name "jabber-roster") (use-local-map jabber-roster-mode-map) (setq buffer-read-only t) (if (fboundp 'run-mode-hooks) (run-mode-hooks 'jabber-roster-mode-hook) (run-hooks 'jabber-roster-mode-hook))) (put 'jabber-roster-mode 'mode-class 'special) ;;;###autoload (defun jabber-switch-to-roster-buffer (&optional jc) "Switch to roster buffer. Optional JC argument is ignored; it's there so this function can be used in `jabber-post-connection-hooks'." (interactive) (if (not (get-buffer jabber-roster-buffer)) (jabber-display-roster) (switch-to-buffer jabber-roster-buffer))) (defun jabber-sort-roster (jc) "sort roster according to online status" (let ((state-data (fsm-get-state-data jc))) (dolist (group (plist-get state-data :roster-groups)) (let ((group-name (car group))) (puthash group-name (sort (gethash group-name (plist-get state-data :roster-hash)) #'jabber-roster-sort-items) (plist-get state-data :roster-hash)))))) (defun jabber-roster-prepare-roster (jc) "make a hash based roster" (let* ((state-data (fsm-get-state-data jc)) (hash (make-hash-table :test 'equal)) (buddies (plist-get state-data :roster)) (all-groups '())) (dolist (buddy buddies) (let ((groups (get buddy 'groups))) (if groups (progn (dolist (group groups) (progn (setq all-groups (append all-groups (list group))) (puthash group (append (gethash group hash) (list buddy)) hash)))) (progn (setq all-groups (append all-groups (list jabber-roster-default-group-name))) (puthash jabber-roster-default-group-name (append (gethash jabber-roster-default-group-name hash) (list buddy)) hash))))) ;; remove duplicates name of group (setq all-groups (sort (remove-duplicates all-groups :test 'string=) 'string<)) ;; put to state-data all-groups as list of list (plist-put state-data :roster-groups (mapcar #'list all-groups)) ;; put to state-data hash-roster (plist-put state-data :roster-hash hash))) (defun jabber-roster-sort-items (a b) "Sort roster items A and B according to `jabber-roster-sort-functions'. Return t if A is less than B." (dolist (fn jabber-roster-sort-functions) (let ((comparison (funcall fn a b))) (cond ((< comparison 0) (return t)) ((> comparison 0) (return nil)))))) (defun jabber-roster-sort-by-status (a b) "Sort roster items by online status. See `jabber-sort-order' for order used." (flet ((order (item) (length (member (get item 'show) jabber-sort-order)))) (let ((a-order (order a)) (b-order (order b))) ;; Note reversed test. Items with longer X-order go first. (cond ((< a-order b-order) 1) ((> a-order b-order) -1) (t 0))))) (defun jabber-roster-sort-by-displayname (a b) "Sort roster items by displayed name." (let ((a-name (jabber-jid-displayname a)) (b-name (jabber-jid-displayname b))) (cond ((string-lessp a-name b-name) -1) ((string= a-name b-name) 0) (t 1)))) (defun jabber-roster-sort-by-group (a b) "Sort roster items by group membership." (flet ((first-group (item) (or (car (get item 'groups)) ""))) (let ((a-group (first-group a)) (b-group (first-group b))) (cond ((string-lessp a-group b-group) -1) ((string= a-group b-group) 0) (t 1))))) (defun jabber-fix-status (status) "Make status strings more readable" (when status (when (string-match "\n+$" status) (setq status (replace-match "" t t status))) (when jabber-remove-newlines (while (string-match "\n" status) (setq status (replace-match " " t t status)))) status)) (defvar jabber-roster-ewoc nil "Ewoc displaying the roster. There is only one; we don't rely on buffer-local variables or such.") (defun jabber-roster-filter-display (buddies) "Filter BUDDIES for items to be displayed in the roster" (remove-if-not (lambda (buddy) (or jabber-show-offline-contacts (get buddy 'connected))) buddies)) (defun jabber-roster-toggle-offline-display () "Toggle display of offline contacts." (interactive) (setq jabber-show-offline-contacts (not jabber-show-offline-contacts)) (jabber-display-roster)) (defun jabber-roster-toggle-binding-display () "Toggle display of the roster binding text." (interactive) (setq jabber-roster-show-bindings (not jabber-roster-show-bindings)) (jabber-display-roster)) (defun jabber-display-roster () "switch to the main jabber buffer and refresh the roster display to reflect the current information" (interactive) (with-current-buffer (get-buffer-create jabber-roster-buffer) (if (not (eq major-mode 'jabber-roster-mode)) (jabber-roster-mode)) (setq buffer-read-only nil) ;; line-number-at-pos is in Emacs >= 21.4. Only used to avoid ;; excessive scrolling when updating roster, so not absolutely ;; necessary. (let ((current-line (and (fboundp 'line-number-at-pos) (line-number-at-pos))) (current-column (current-column))) (erase-buffer) (setq jabber-roster-ewoc nil) (when jabber-roster-show-title (insert (jabber-propertize "Jabber roster" 'face 'jabber-title-large) "\n")) (when jabber-roster-show-bindings (insert "RET Open chat buffer C-k Delete roster item e Edit item s Send subscription request q Bury buffer i Get disco items I Get disco info b Browse j Join groupchat (MUC) v Get client version a Send presence o Show offline contacts on/off C-c C-c Chat menu C-c C-m Multi-User Chat menu C-c C-i Info menu C-c C-r Roster menu C-c C-s Service menu H Toggle displaying this text ")) (insert "__________________________________\n\n") (if (null jabber-connections) (insert "Not connected\n") (let ((map (make-sparse-keymap))) (define-key map [mouse-2] #'jabber-send-presence) (insert (jabber-propertize (concat (format " - %s" (cdr (assoc *jabber-current-show* jabber-presence-strings))) (if (not (zerop (length *jabber-current-status*))) (format " (%s)" (jabber-fix-status *jabber-current-status*))) " -") 'face (or (cdr (assoc *jabber-current-show* jabber-presence-faces)) 'jabber-roster-user-online) ;;'mouse-face (cons 'background-color "light grey") 'keymap map) "\n"))) (dolist (jc jabber-connections) ;; use a hash-based roster (when (not (plist-get (fsm-get-state-data jc) :roster-hash)) (jabber-roster-prepare-roster jc)) ;; We sort everything before putting it in the ewoc (jabber-sort-roster jc) (let ((before-ewoc (point)) (ewoc (ewoc-create (lexical-let ((jc jc)) (lambda (data) (let* ((group (car data)) (group-name (car group)) (buddy (car (cdr data)))) (jabber-display-roster-entry jc group-name buddy)))) (concat (jabber-propertize (concat (plist-get (fsm-get-state-data jc) :username) "@" (plist-get (fsm-get-state-data jc) :server)) 'face 'jabber-title-medium) "\n__________________________________\n") "__________________________________")) (new-groups '())) (plist-put(fsm-get-state-data jc) :roster-ewoc ewoc) (dolist (group (plist-get (fsm-get-state-data jc) :roster-groups)) (let* ((group-name (car group)) (buddies (jabber-roster-filter-display (gethash group-name (plist-get (fsm-get-state-data jc) :roster-hash))))) (when (or jabber-roster-show-empty-group (> (length buddies) 0)) (let ((group-node (ewoc-enter-last ewoc (list group nil)))) (if (not (find group-name (plist-get (fsm-get-state-data jc) :roster-roll-groups) :test 'string=)) (dolist (buddy (reverse buddies)) (ewoc-enter-after ewoc group-node (list group buddy)))))))) (goto-char (point-max)) (insert "\n") (put-text-property before-ewoc (point) 'jabber-account jc))) (goto-char (point-min)) (setq buffer-read-only t) (if (interactive-p) (dolist (hook '(jabber-info-message-hooks jabber-alert-info-message-hooks)) (run-hook-with-args hook 'roster (current-buffer) (funcall jabber-alert-info-message-function 'roster (current-buffer))))) (when current-line ;; Go back to previous line - don't use goto-line, since it ;; sets the mark. (goto-char (point-min)) (forward-line (1- current-line)) ;; ...and go back to previous column (move-to-column current-column))))) (defun jabber-display-roster-entry (jc group-name buddy) "Format and insert a roster entry for BUDDY at point. BUDDY is a JID symbol." (if buddy (let ((buddy-str (format-spec jabber-roster-line-format (list (cons ?a (jabber-propertize " " 'display (get buddy 'avatar))) (cons ?c (if (get buddy 'connected) "*" " ")) (cons ?u (cdr (assoc (or (get buddy 'subscription) "none") jabber-roster-subscription-display))) (cons ?n (if (> (length (get buddy 'name)) 0) (get buddy 'name) (symbol-name buddy))) (cons ?j (symbol-name buddy)) (cons ?r (or (get buddy 'resource) "")) (cons ?s (or (cdr (assoc (get buddy 'show) jabber-presence-strings)) (get buddy 'show))) (cons ?S (if (get buddy 'status) (jabber-fix-status (get buddy 'status)) "")) )))) (add-text-properties 0 (length buddy-str) (list 'face (or (cdr (assoc (get buddy 'show) jabber-presence-faces)) 'jabber-roster-user-online) ;;'mouse-face ;;(cons 'background-color "light grey") 'help-echo (symbol-name buddy) 'jabber-jid (symbol-name buddy) 'jabber-account jc) buddy-str) (insert buddy-str) (when (or (eq jabber-show-resources 'always) (and (eq jabber-show-resources 'sometimes) (> (jabber-count-connected-resources buddy) 1))) (dolist (resource (get buddy 'resources)) (when (plist-get (cdr resource) 'connected) (let ((resource-str (format-spec jabber-resource-line-format (list (cons ?c "*") (cons ?n (if (> (length (get buddy 'name)) 0) (get buddy 'name) (symbol-name buddy))) (cons ?j (symbol-name buddy)) (cons ?r (if (> (length (car resource)) 0) (car resource) "empty")) (cons ?s (or (cdr (assoc (plist-get (cdr resource) 'show) jabber-presence-strings)) (plist-get (cdr resource) 'show))) (cons ?S (if (plist-get (cdr resource) 'status) (jabber-fix-status (plist-get (cdr resource) 'status)) "")) (cons ?p (number-to-string (plist-get (cdr resource) 'priority))))))) (add-text-properties 0 (length resource-str) (list 'face (or (cdr (assoc (plist-get (cdr resource) 'show) jabber-presence-faces)) 'jabber-roster-user-online) 'jabber-jid (format "%s/%s" (symbol-name buddy) (car resource)) 'jabber-account jc) resource-str) (insert "\n" resource-str)))))) (let ((group-name (or group-name jabber-roster-default-group-name))) (add-text-properties 0 (length group-name) (list 'face 'jabber-title-small 'jabber-group group-name 'jabber-account jc) group-name) (insert group-name)))) ;;;###autoload (defun jabber-roster-update (jc new-items changed-items deleted-items) "Update roster, in memory and on display. Add NEW-ITEMS, update CHANGED-ITEMS and remove DELETED-ITEMS, all three being lists of JID symbols." (let* ((roster (plist-get (fsm-get-state-data jc) :roster)) (hash (plist-get (fsm-get-state-data jc) :roster-hash)) (ewoc (plist-get (fsm-get-state-data jc) :roster-ewoc)) (all-groups (plist-get (fsm-get-state-data jc) :roster-groups)) (terminator (lambda (deleted-items) (dolist (delete-this deleted-items) (let ((groups (get delete-this 'groups)) (terminator (lambda (g) (let* ((group (or g jabber-roster-default-group-name)) (buddies (gethash group hash))) (when (not buddies) (setq new-groups (append new-groups (list group)))) (puthash group (delq delete-this buddies) hash))))) (if groups (dolist (group groups) (terminator group)) (terminator groups))))))) ;; fix a old-roster (dolist (delete-this deleted-items) (setq roster (delq delete-this roster))) (setq roster (append new-items roster)) (plist-put (fsm-get-state-data jc) :roster roster) ;; update a hash-roster (if (not hash) (jabber-roster-prepare-roster jc) (when jabber-roster-debug (message "update hash-based roster")) ;; delete items (dolist (delete-this (append deleted-items changed-items)) (let ((jid (symbol-name delete-this))) (when jabber-roster-debug (message (concat "delete jid: " jid))) (dolist (group (mapcar (lambda (g) (car g)) all-groups)) (when jabber-roster-debug (message (concat "try to delete jid: " jid " from group " group))) (puthash group (delq delete-this (gethash group hash)) hash)))) ;; insert changed-items (dolist (insert-this (append changed-items new-items)) (let ((jid (symbol-name insert-this))) (when jabber-roster-debug (message (concat "insert jid: " jid))) (dolist (group (or (get insert-this 'groups) (list jabber-roster-default-group-name))) (when jabber-roster-debug (message (concat "insert jid: " jid " to group " group))) (puthash group (append (gethash group hash) (list insert-this)) hash) (setq all-groups (append all-groups (list (list group))))))) (when jabber-roster-debug (message "remove duplicates from new group")) (setq all-groups (sort (remove-duplicates all-groups :test (lambda (g1 g2) (let ((g1-name (car g1)) (g2-name (car g2))) (string= g1-name g2-name)))) (lambda (g1 g2) (let ((g1-name (car g1)) (g2-name (car g2))) (string< g1-name g2-name))))) (plist-put (fsm-get-state-data jc) :roster-groups all-groups)) (when jabber-roster-debug (message "re display roster")) ;; recreate roster buffer (jabber-display-roster))) (defalias 'jabber-presence-update-roster 'ignore) ;;jabber-presence-update-roster is not needed anymore. ;;Its work is done in `jabber-process-presence'." (make-obsolete 'jabber-presence-update-roster 'ignore) (defun jabber-go-to-next-jid () "Move the cursor to the next jid in the buffer" (interactive) (let ((next (next-single-property-change (point) 'jabber-jid))) (when (and next (not (get-text-property next 'jabber-jid))) (setq next (next-single-property-change next 'jabber-jid))) (unless next (setq next (next-single-property-change (point-min) 'jabber-jid))) (if next (goto-char (1+ next)) (goto-char (point-min))))) (defun jabber-go-to-previous-jid () "Move the cursor to the previous jid in the buffer" (interactive) (let ((previous (previous-single-property-change (point) 'jabber-jid))) (when (and previous (not (get-text-property previous 'jabber-jid))) (setq previous (previous-single-property-change previous 'jabber-jid))) (unless previous (setq previous (previous-single-property-change (point-max) 'jabber-jid))) (if previous (goto-char previous) (goto-char (point-max))))) (provide 'jabber-roster) ;;; arch-tag: 096af063-0526-4dd2-90fd-bc6b5ba07d32 emacs-jabber-0.8.0/jabber-sasl.el0000644000175100017510000001225311133727374013477 00000000000000;; jabber-sasl.el - SASL authentication ;; Copyright (C) 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'cl) ;;; This file uses sasl.el from FLIM or Gnus. If it can't be found, ;;; jabber-core.el won't use the SASL functions. (eval-and-compile (condition-case nil (require 'sasl) (error nil))) ;;; Alternatives to FLIM would be the command line utility of GNU SASL, ;;; or anything the Gnus people decide to use. ;;; See XMPP-CORE and XMPP-IM for details about the protocol. (require 'jabber-xml) (defun jabber-sasl-start-auth (jc stream-features) ;; Find a suitable common mechanism. (let* ((mechanism-elements (car (jabber-xml-get-children stream-features 'mechanisms))) (mechanisms (mapcar (lambda (tag) (car (jabber-xml-node-children tag))) (jabber-xml-get-children mechanism-elements 'mechanism))) (mechanism (if (and (member "ANONYMOUS" mechanisms) (yes-or-no-p "Use anonymous authentication? ")) (sasl-find-mechanism '("ANONYMOUS")) (sasl-find-mechanism mechanisms)))) ;; No suitable mechanism? (if (null mechanism) ;; Maybe we can use legacy authentication (let ((iq-auth (find "http://jabber.org/features/iq-auth" (jabber-xml-get-children stream-features 'auth) :key #'jabber-xml-get-xmlns :test #'string=)) ;; Or maybe we have to use STARTTLS, but can't (starttls (find "urn:ietf:params:xml:ns:xmpp-tls" (jabber-xml-get-children stream-features 'starttls) :key #'jabber-xml-get-xmlns :test #'string=))) (cond (iq-auth (fsm-send jc :use-legacy-auth-instead)) (starttls (message "STARTTLS encryption required, but disabled/non-functional at our end") (fsm-send jc :authentication-failure)) (t (message "Authentication failure: no suitable SASL mechanism found") (fsm-send jc :authentication-failure)))) ;; Watch for plaintext logins over unencrypted connections (if (and (not (plist-get (fsm-get-state-data jc) :encrypted)) (member (sasl-mechanism-name mechanism) '("PLAIN" "LOGIN")) (not (yes-or-no-p "Jabber server only allows cleartext password transmission! Continue? "))) (fsm-send jc :authentication-failure) ;; Start authentication. (let* (passphrase (client (sasl-make-client mechanism (plist-get (fsm-get-state-data jc) :username) "xmpp" (plist-get (fsm-get-state-data jc) :server))) (sasl-read-passphrase (jabber-sasl-read-passphrase-closure jc (lambda (p) (setq passphrase (copy-sequence p)) p))) (step (sasl-next-step client nil))) (jabber-send-sexp jc `(auth ((xmlns . "urn:ietf:params:xml:ns:xmpp-sasl") (mechanism . ,(sasl-mechanism-name mechanism))) ,(when (sasl-step-data step) (base64-encode-string (sasl-step-data step) t)))) (list client step passphrase)))))) (defun jabber-sasl-read-passphrase-closure (jc remember) "Return a lambda function suitable for `sasl-read-passphrase' for JC. Call REMEMBER with the password. REMEMBER is expected to return it as well." (lexical-let ((password (plist-get (fsm-get-state-data jc) :password)) (bare-jid (jabber-connection-bare-jid jc)) (remember remember)) (if password (lambda (prompt) (funcall remember (copy-sequence password))) (lambda (prompt) (funcall remember (jabber-read-password bare-jid)))))) (defun jabber-sasl-process-input (jc xml-data sasl-data) (let* ((client (first sasl-data)) (step (second sasl-data)) (passphrase (third sasl-data)) (sasl-read-passphrase (jabber-sasl-read-passphrase-closure jc (lambda (p) (setq passphrase (copy-sequence p)) p)))) (cond ((eq (car xml-data) 'challenge) (sasl-step-set-data step (base64-decode-string (car (jabber-xml-node-children xml-data)))) (setq step (sasl-next-step client step)) (jabber-send-sexp jc `(response ((xmlns . "urn:ietf:params:xml:ns:xmpp-sasl")) ,(when (sasl-step-data step) (base64-encode-string (sasl-step-data step) t))))) ((eq (car xml-data) 'failure) (message "SASL authentication failure: %s" (jabber-xml-node-name (car (jabber-xml-node-children xml-data)))) (fsm-send jc :authentication-failure)) ((eq (car xml-data) 'success) (message "Authentication succeeded") (fsm-send jc (cons :authentication-success passphrase)))) (list client step passphrase))) (provide 'jabber-sasl) ;;; arch-tag: 2a4a234d-34d3-49dd-950d-518c899c0fd0 emacs-jabber-0.8.0/jabber-sawfish.el0000644000175100017510000000327111133727374014201 00000000000000;; jabber-sawfish.el - emacs-jabber interface to sawfish ;; Copyright (C) 2005 - Mario Domenech Goulart ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'jabber-alert)) (defcustom jabber-sawfish-display-time 3 "Time in seconds for displaying a jabber message through the Sawfish window manager." :type 'integer :group 'jabber-alerts) (defun jabber-sawfish-display-message (message) "Displays MESSAGE through the Sawfish window manager." (let ((process-connection-type nil)) (start-process-shell-command "jabber-sawfish" nil "echo" (concat "'(progn (require (quote timers)) (display-message \"" message "\")(make-timer (lambda () (display-message nil)) " (number-to-string jabber-sawfish-display-time) "))' | sawfish-client - &> /dev/null")))) (define-jabber-alert sawfish "Display a message through the Sawfish window manager" 'jabber-sawfish-display-message) (provide 'jabber-sawfish) ;; arch-tag: 4F0154ED-5D05-11D9-9E6B-000A95C2FCD0 emacs-jabber-0.8.0/jabber-screen.el0000644000175100017510000000226511133727374014016 00000000000000;; jabber-screen.el - emacs-jabber interface to screen ;; Copyright (C) 2005 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'jabber-alert)) (defun jabber-screen-message (msg) "Show MSG in screen" (call-process "screen" nil nil nil "-X" "echo" msg)) (define-jabber-alert screen "Show a message through the Screen terminal manager" 'jabber-screen-message) (provide 'jabber-screen) ;; arch-tag: B576ADDA-5D04-11D9-AA52-000A95C2FCD0 emacs-jabber-0.8.0/jabber-search.el0000644000175100017510000001024111133727374013775 00000000000000;; jabber-search.el - searching by JEP-0055, with x:data support ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; Copyright (C) 2003, 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-register) (add-to-list 'jabber-jid-service-menu (cons "Search directory" 'jabber-get-search)) (defun jabber-get-search (jc to) "Send IQ get request in namespace \"jabber:iq:search\"." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Search what database: "))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:search"))) #'jabber-process-data #'jabber-process-register-or-search #'jabber-report-success "Search field retrieval")) ;; jabber-process-register-or-search logically comes here, rendering ;; the search form, but since register and search are so similar, ;; having two functions would be serious code duplication. See ;; jabber-register.el. ;; jabber-submit-search is called when the "submit" button of the ;; search form is activated. (defun jabber-submit-search (&rest ignore) "Submit search. See `jabber-process-register-or-search'." (let ((text (concat "Search at " jabber-submit-to))) (jabber-send-iq jabber-buffer-connection jabber-submit-to "set" (cond ((eq jabber-form-type 'register) `(query ((xmlns . "jabber:iq:search")) ,@(jabber-parse-register-form))) ((eq jabber-form-type 'xdata) `(query ((xmlns . "jabber:iq:search")) ,(jabber-parse-xdata-form))) (t (error "Unknown form type: %s" jabber-form-type))) #'jabber-process-data #'jabber-process-search-result #'jabber-report-success text)) (message "Search sent")) (defun jabber-process-search-result (jc xml-data) "Receive and display search results." ;; This function assumes that all search results come in one packet, ;; which is not necessarily the case. (let ((query (jabber-iq-query xml-data)) (have-xdata nil) xdata fields (jid-fields 0)) ;; First, check for results in jabber:x:data form. (dolist (x (jabber-xml-get-children query 'x)) (when (string= (jabber-xml-get-attribute x 'xmlns) "jabber:x:data") (setq have-xdata t) (setq xdata x))) (if have-xdata (jabber-render-xdata-search-results xdata) (insert (jabber-propertize "Search results" 'face 'jabber-title-medium) "\n") (setq fields '((first . (label "First name" column 0)) (last . (label "Last name" column 15)) (nick . (label "Nickname" column 30)) (jid . (label "JID" column 45)) (email . (label "E-mail" column 65)))) (setq jid-fields 1) (dolist (field-cons fields) (indent-to (plist-get (cdr field-cons) 'column) 1) (insert (jabber-propertize (plist-get (cdr field-cons) 'label) 'face 'bold))) (insert "\n\n") ;; Now, the items (dolist (item (jabber-xml-get-children query 'item)) (let ((start-of-line (point)) jid) (dolist (field-cons fields) (let ((field-plist (cdr field-cons)) (value (if (eq (car field-cons) 'jid) (setq jid (jabber-xml-get-attribute item 'jid)) (car (jabber-xml-node-children (car (jabber-xml-get-children item (car field-cons)))))))) (indent-to (plist-get field-plist 'column) 1) (if value (insert value)))) (if jid (put-text-property start-of-line (point) 'jabber-jid jid)) (insert "\n")))))) (provide 'jabber-search) ;;; arch-tag: c39e9241-ab6f-4ac5-b1ba-7908bbae009c emacs-jabber-0.8.0/jabber-si-client.el0000644000175100017510000000534211133727374014425 00000000000000;; jabber-si-client.el - send stream requests, by JEP-0095 ;; Copyright (C) 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-iq) (require 'jabber-feature-neg) (require 'jabber-si-common) (defun jabber-si-initiate (jc jid profile-namespace profile-data profile-function &optional mime-type) "Try to initiate a stream to JID. PROFILE-NAMESPACE is, well, the namespace of the profile to use. PROFILE-DATA is the XML data to send within the SI request. PROFILE-FUNCTION is the \"connection established\" function. See `jabber-si-stream-methods'. MIME-TYPE is the MIME type to specify. Returns the SID." (let ((sid (apply 'format "emacs-sid-%d.%d.%d" (current-time)))) (jabber-send-iq jc jid "set" `(si ((xmlns . "http://jabber.org/protocol/si") (id . ,sid) ,(if mime-type (cons 'mime-type mime-type)) (profile . ,profile-namespace)) ,profile-data (feature ((xmlns . "http://jabber.org/protocol/feature-neg")) ,(jabber-fn-encode (list (cons "stream-method" (mapcar 'car jabber-si-stream-methods))) 'request))) #'jabber-si-initiate-process (cons profile-function sid) ;; XXX: use other function here? #'jabber-report-success "Stream initiation") sid)) (defun jabber-si-initiate-process (jc xml-data closure-data) "Act on response to our SI query." (let* ((profile-function (car closure-data)) (sid (cdr closure-data)) (from (jabber-xml-get-attribute xml-data 'from)) (query (jabber-iq-query xml-data)) (feature-node (car (jabber-xml-get-children query 'feature))) (feature-alist (jabber-fn-parse feature-node 'response)) (chosen-method (cadr (assoc "stream-method" feature-alist))) (method-data (assoc chosen-method jabber-si-stream-methods))) ;; Our work is done. Hand it over to the stream method. (let ((stream-negotiate (nth 1 method-data))) (funcall stream-negotiate jc from sid profile-function)))) (provide 'jabber-si-client) ;;; arch-tag: e14ec451-3f18-4f36-b92a-e8a8aa1f5acd emacs-jabber-0.8.0/jabber-si-common.el0000644000175100017510000000375511133727374014445 00000000000000;;; jabber-si-common.el --- stream initiation (JEP-0095) ;; Copyright (C) 2006 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. (defvar jabber-si-stream-methods nil "Supported SI stream methods. Each entry is a list, containing: * The namespace URI of the stream method * Active initiation function * Passive initiation function The active initiation function should initiate the connection, while the passive initiation function should wait for an incoming connection. Both functions take the same arguments: * JID of peer * SID * \"connection established\" function The \"connection established\" function should be called when the stream has been established and data can be transferred. It is part of the profile, and takes the following arguments: * JID of peer * SID * Either: - \"send data\" function, with one string argument - an error message, when connection failed It returns an \"incoming data\" function. The \"incoming data\" function should be called when data arrives on the stream. It takes these arguments: * JID of peer * SID * A string containing the received data, or nil on EOF If it returns nil, the stream should be closed.") (provide 'jabber-si-common) ;; arch-tag: 9e7a5c8a-bdde-11da-8030-000a95c2fcd0 ;;; jabber-si-common.el ends here emacs-jabber-0.8.0/jabber-si-server.el0000644000175100017510000000735511133727374014463 00000000000000;; jabber-si-server.el - handle incoming stream requests, by JEP-0095 ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; Copyright (C) 2003, 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-iq) (require 'jabber-disco) (require 'jabber-feature-neg) (require 'jabber-si-common) (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/si") ;; Now, stream methods push data to profiles. It could be the other ;; way around; not sure which is better. (defvar jabber-si-profiles nil "Supported SI profiles. Each entry is a list, containing: * The namespace URI of the profile * Accept function, taking entire IQ stanza, and signalling a 'forbidden' error if request is declined; returning an XML node to return in response, or nil of none needed * \"Connection established\" function. See `jabber-si-stream-methods'.") (add-to-list 'jabber-iq-set-xmlns-alist (cons "http://jabber.org/protocol/si" 'jabber-si-process)) (defun jabber-si-process (jc xml-data) (let* ((to (jabber-xml-get-attribute xml-data 'from)) (id (jabber-xml-get-attribute xml-data 'id)) (query (jabber-iq-query xml-data)) (profile (jabber-xml-get-attribute query 'profile)) (si-id (jabber-xml-get-attribute query 'id)) (feature (car (jabber-xml-get-children query 'feature)))) (message "Receiving SI with profile '%s'" profile) (let (stream-method ;; Find profile (profile-data (assoc profile jabber-si-profiles))) ;; Now, feature negotiation for stream type (errors ;; don't match JEP-0095, so convert) (condition-case err (setq stream-method (jabber-fn-intersection (jabber-fn-parse feature 'request) (list (cons "stream-method" (mapcar 'car jabber-si-stream-methods))))) (jabber-error (jabber-signal-error "cancel" 'bad-request nil '((no-valid-streams ((xmlns . "http://jabber.org/protocol/si"))))))) (unless profile-data ;; profile not understood (jabber-signal-error "cancel" 'bad-request nil '((bad-profile ((xmlns . "http://jabber.org/protocol/si")))))) (let* ((profile-accept-function (nth 1 profile-data)) ;; accept-function might throw a "forbidden" error ;; on user cancel (profile-response (funcall profile-accept-function jc xml-data)) (profile-connected-function (nth 2 profile-data)) (stream-method-id (nth 1 (assoc "stream-method" stream-method))) (stream-data (assoc stream-method-id jabber-si-stream-methods)) (stream-accept-function (nth 2 stream-data))) ;; prepare stream for the transfer (funcall stream-accept-function jc to si-id profile-connected-function) ;; return result of feature negotiation of stream type (jabber-send-iq jc to "result" `(si ((xmlns . "http://jabber.org/protocol/si")) ,@profile-response (feature ((xmlns . "http://jabber.org/protocol/feature-neg")) ,(jabber-fn-encode stream-method 'response))) nil nil nil nil id) )))) (provide 'jabber-si-server) ;;; arch-tag: d3c75c66-4052-4cf5-8f04-8765adfc8b96 emacs-jabber-0.8.0/jabber-socks5.el0000644000175100017510000006174511133727374013756 00000000000000;; jabber-socks5.el - SOCKS5 bytestreams by JEP-0065 ;; Copyright (C) 2003, 2004, 2007 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-iq) (require 'jabber-disco) (require 'jabber-si-server) (require 'jabber-si-client) (require 'jabber-newdisco) (require 'fsm) (eval-when-compile (require 'cl)) (defvar jabber-socks5-pending-sessions nil "List of pending sessions. Each entry is a list, containing: * Stream ID * Full JID of initiator * State machine managing the session") (defvar jabber-socks5-active-sessions nil "List of active sessions. Each entry is a list, containing: * Network connection * Stream ID * Full JID of initiator * Profile data function") (defcustom jabber-socks5-proxies nil "JIDs of JEP-0065 proxies to use for file transfer. Put preferred ones first." :type '(repeat string) :group 'jabber ; :set 'jabber-socks5-set-proxies) ) (defvar jabber-socks5-proxies-data nil "Alist containing information about proxies. Keys of the alist are strings, the JIDs of the proxies. Values are \"streamhost\" XML nodes.") (add-to-list 'jabber-advertised-features "http://jabber.org/protocol/bytestreams") (add-to-list 'jabber-si-stream-methods (list "http://jabber.org/protocol/bytestreams" 'jabber-socks5-client-1 'jabber-socks5-accept)) (defun jabber-socks5-set-proxies (symbol value) "Set `jabber-socks5-proxies' and query proxies. This is the set function of `jabber-socks5-proxies-data'." (set-default symbol value) (when *jabber-connected* (jabber-socks5-query-all-proxies))) (defun jabber-socks5-query-all-proxies (jc &optional callback) "Ask all proxies in `jabber-socks5-proxies' for connection information. If CALLBACK is non-nil, call it with no arguments when all proxies have answered." (interactive (list (jabber-read-account))) (setq jabber-socks5-proxies-data nil) (dolist (proxy jabber-socks5-proxies) (jabber-socks5-query-proxy jc proxy callback))) (defun jabber-socks5-query-proxy (jc jid &optional callback) "Query the SOCKS5 proxy specified by JID for IP and port number." (jabber-send-iq jc jid "get" '(query ((xmlns . "http://jabber.org/protocol/bytestreams"))) #'jabber-socks5-process-proxy-response (list callback t) #'jabber-socks5-process-proxy-response (list callback nil))) (defun jabber-socks5-process-proxy-response (jc xml-data closure-data) "Process response from proxy query." (let* ((query (jabber-iq-query xml-data)) (from (jabber-xml-get-attribute xml-data 'from)) (streamhosts (jabber-xml-get-children query 'streamhost))) (let ((existing-entry (assoc from jabber-socks5-proxies-data))) (when existing-entry (setq jabber-socks5-proxies-data (delq existing-entry jabber-socks5-proxies-data)))) (destructuring-bind (callback successp) closure-data (when successp (setq jabber-socks5-proxies-data (cons (cons from streamhosts) jabber-socks5-proxies-data))) (message "%s from %s. %d of %d proxies have answered." (if successp "Response" "Error") from (length jabber-socks5-proxies-data) (length jabber-socks5-proxies)) (when (and callback (= (length jabber-socks5-proxies-data) (length jabber-socks5-proxies))) (funcall callback))))) (define-state-machine jabber-socks5 :start ((jc jid sid profile-function role) "Start JEP-0065 bytestream with JID. SID is the session ID used. PROFILE-FUNCTION is the function to call upon success. See `jabber-si-stream-methods'. ROLE is either :initiator or :target. The initiator sends an IQ set; the target waits for one." (let ((new-state-data (list :jc jc :jid jid :sid sid :profile-function profile-function :role role)) (new-state ;; We want information about proxies; it might be needed in ;; various situations. (cond ((null jabber-socks5-proxies) ;; We know no proxy addresses. Try to find them by disco. 'seek-proxies) ((null jabber-socks5-proxies-data) ;; We need to query the proxies for addresses. 'query-proxies) ;; So, we have our proxies. (t 'initiate)))) (list new-state new-state-data nil)))) (defun jabber-socks5-accept (jc jid sid profile-function) "Remember that we are waiting for connection from JID, with stream id SID" ;; asking the user for permission is done in the profile (add-to-list 'jabber-socks5-pending-sessions (list sid jid (start-jabber-socks5 jc jid sid profile-function :target)))) (define-enter-state jabber-socks5 seek-proxies (fsm state-data) ;; Look for items at the server. (let* ((jc (plist-get state-data :jc)) (server (jabber-jid-server (jabber-connection-jid jc)))) (jabber-disco-get-items jc server nil (lambda (jc fsm result) (fsm-send-sync fsm (cons :items result))) fsm)) ;; Spend no more than five seconds looking for a proxy. (list state-data 5)) (define-state jabber-socks5 seek-proxies (fsm state-data event callback) "Collect disco results, looking for a bytestreams proxy." ;; We put the number of outstanding requests as :remaining-info in ;; the state-data plist. (cond ;; We're not ready to handle the IQ stanza yet ((eq (car-safe event) :iq) :defer) ;; Got list of items at the server. ((eq (car-safe event) :items) (dolist (entry (cdr event)) ;; Each entry is ["name" "jid" "node"]. We send a disco info ;; request to everything without a node. (when (null (aref entry 2)) (lexical-let ((jid (aref entry 1))) (jabber-disco-get-info (plist-get state-data :jc) jid nil (lambda (jc fsm result) (fsm-send-sync fsm (list :info jid result))) fsm)))) ;; Remember number of requests sent. But if none, we just go on. (if (cdr event) (list 'seek-proxies (plist-put state-data :remaining-info (length (cdr event))) :keep) (list 'initiate state-data nil))) ;; Got disco info from an item at the server. ((eq (car-safe event) :info) (fsm-debug-output "got disco event") ;; Count the response. (plist-put state-data :remaining-info (1- (plist-get state-data :remaining-info))) (unless (eq (first (third event)) 'error) (let ((identities (first (third event)))) ;; Is it a bytestream proxy? (when (dolist (identity identities) (when (and (string= (aref identity 1) "proxy") (string= (aref identity 2) "bytestreams")) (return t))) ;; Yes, it is. Add it to the list. (push (second event) jabber-socks5-proxies)))) ;; Wait for more responses, if any are to be expected. (if (zerop (plist-get state-data :remaining-info)) ;; No more... go on to querying the proxies. (list 'query-proxies state-data nil) ;; We expect more responses... (list 'seek-proxies state-data :keep))) ((eq event :timeout) ;; We can't wait anymore... (list 'query-proxies state-data nil)))) (define-enter-state jabber-socks5 query-proxies (fsm state-data) (jabber-socks5-query-all-proxies (plist-get state-data :jc) (lexical-let ((fsm fsm)) (lambda () (fsm-send-sync fsm :proxies)))) (list state-data 5)) (define-state jabber-socks5 query-proxies (fsm state-data event callback) "Query proxies in `jabber-socks5-proxies'." (cond ;; Can't handle the iq stanza yet... ((eq (car-safe event) :iq) :defer) ((eq (car-safe event) :info) ;; stray event... do nothing (list 'query-proxies state-data :keep)) ;; Got response/error from all proxies, or timeout ((memq event '(:proxies :timeout)) (list 'initiate state-data nil)))) (define-enter-state jabber-socks5 initiate (fsm state-data) ;; Sort the alist jabber-socks5-proxies-data such that the ;; keys are in the same order as in jabber-socks5-proxies. (setq jabber-socks5-proxies-data (sort jabber-socks5-proxies-data #'(lambda (a b) (> (length (member (car a) jabber-socks5-proxies)) (length (member (car b) jabber-socks5-proxies)))))) ;; If we're the initiator, send initiation stanza. (when (eq (plist-get state-data :role) :initiator) ;; This is where initiation of server sockets would go (jabber-send-iq (plist-get state-data :jc) (plist-get state-data :jid) "set" `(query ((xmlns . "http://jabber.org/protocol/bytestreams") (sid . ,(plist-get state-data :sid))) ,@(mapcar #'(lambda (proxy) (mapcar #'(lambda (streamhost) (list 'streamhost (list (cons 'jid (jabber-xml-get-attribute streamhost 'jid)) (cons 'host (jabber-xml-get-attribute streamhost 'host)) (cons 'port (jabber-xml-get-attribute streamhost 'port))) ;; (proxy ((xmlns . "http://affinix.com/jabber/stream"))) )) (cdr proxy))) jabber-socks5-proxies-data) ;; (fast ((xmlns . "http://affinix.com/jabber/stream"))) ) (lexical-let ((fsm fsm)) (lambda (jc xml-data closure-data) (fsm-send-sync fsm (list :iq xml-data)))) nil ;; TODO: error handling #'jabber-report-success "SOCKS5 negotiation")) ;; If we're the target, we just wait for an incoming stanza. (list state-data nil)) (add-to-list 'jabber-iq-set-xmlns-alist (cons "http://jabber.org/protocol/bytestreams" 'jabber-socks5-process)) (defun jabber-socks5-process (jc xml-data) "Accept IQ get for SOCKS5 bytestream" (let* ((jid (jabber-xml-get-attribute xml-data 'from)) (id (jabber-xml-get-attribute xml-data 'id)) (query (jabber-iq-query xml-data)) (sid (jabber-xml-get-attribute query 'sid)) (session (dolist (pending-session jabber-socks5-pending-sessions) (when (and (equal sid (nth 0 pending-session)) (equal jid (nth 1 pending-session))) (return pending-session))))) ;; check that we really are expecting this session (unless session (jabber-signal-error "auth" 'not-acceptable)) (setq jabber-socks5-pending-sessions (delq session jabber-socks5-pending-sessions)) (fsm-send-sync (nth 2 session) (list :iq xml-data)) ;; find streamhost to connect to ;; (let* ((streamhosts (jabber-xml-get-children query 'streamhost)) ;; (streamhost (dolist (streamhost streamhosts) ;; (let ((connection (jabber-socks5-connect streamhost sid jid (concat jabber-username "@" jabber-server "/" jabber-resource)))) ;; (when connection ;; ;; We select the first streamhost that we are able to connect to. ;; (push (list connection sid jid profile-data-function) ;; jabber-socks5-active-sessions) ;; ;; Now set the filter, for the rest of the output ;; (set-process-filter connection #'jabber-socks5-filter) ;; (set-process-sentinel connection #'jabber-socks5-sentinel) ;; (return streamhost)))))) ;; (unless streamhost ;; (jabber-signal-error "cancel" 'item-not-found)) ;; ;; tell initiator which streamhost we use ;; (jabber-send-iq jid "result" ;; `(query ((xmlns . "http://jabber.org/protocol/bytestreams")) ;; (streamhost-used ((jid . ,(jabber-xml-get-attribute streamhost 'jid))))) ;; nil nil nil nil id) ;; ;; now, as data is sent, it will be passed to the profile. ;; ) )) (define-state jabber-socks5 initiate (fsm state-data event callback) (let* ((jc (plist-get state-data :jc)) (jc-data (fsm-get-state-data jc)) (our-jid (concat (plist-get jc-data :username) "@" (plist-get jc-data :server) "/" (plist-get jc-data :resource))) (their-jid (plist-get state-data :jid)) (initiator-jid (if (eq (plist-get state-data :role) :initiator) our-jid their-jid)) (target-jid (if (eq (plist-get state-data :role) :initiator) their-jid our-jid))) (cond ;; Stray event... ((memq (car-safe event) '(:proxy :info)) (list 'initiate state-data :keep)) ;; Incoming IQ ((eq (car-safe event) :iq) (let ((xml-data (second event))) ;; This is either type "set" (with a list of streamhosts to ;; use), or a "result" (indicating the streamhost finally used ;; by the other party). (cond ((string= (jabber-xml-get-attribute xml-data 'type) "set") ;; A "set" makes sense if we're the initiator and offered ;; Psi's "fast mode". We don't yet, though, so this is only ;; for target. (dolist (streamhost (jabber-xml-get-children (jabber-iq-query xml-data) 'streamhost)) (jabber-xml-let-attributes (jid host port) streamhost ;; This is where we would attempt to support zeroconf (when (and jid host port) (start-jabber-socks5-connection jc initiator-jid target-jid jid (plist-get state-data :sid) host port fsm)))) (list 'wait-for-connection (plist-put state-data :iq-id (jabber-xml-get-attribute xml-data 'id)) 30)) ((string= (jabber-xml-get-attribute xml-data 'type) "result") ;; The other party has decided what streamhost to use. (let* ((proxy-used (jabber-xml-get-attribute (jabber-xml-path xml-data '(query streamhost-used)) 'jid)) ;; If JID is our own JID, we have probably already detected ;; what connection to use. But that is a later problem... (streamhosts (cdr (assoc proxy-used jabber-socks5-proxies-data)))) ;; Try to connect to all addresses of this proxy... (dolist (streamhost streamhosts) (jabber-xml-let-attributes (jid host port) streamhost (when (and jid host port) (start-jabber-socks5-connection jc initiator-jid target-jid jid (plist-get state-data :sid) host port fsm))))) (list 'wait-for-connection state-data 30)))))))) (define-state-machine jabber-socks5-connection :start ((jc initiator-jid target-jid streamhost-jid sid host port socks5-fsm) "Connect to a single JEP-0065 streamhost." (let ((coding-system-for-read 'binary) (coding-system-for-write 'binary)) ;; make-network-process, which we really want, for asynchronous ;; connection and such, was introduced in Emacs 22. (if (fboundp 'make-network-process) (let ((connection (make-network-process :name "socks5" :buffer nil :host host :service (string-to-number port) :nowait t :filter (fsm-make-filter fsm) :sentinel (fsm-make-sentinel fsm)))) (list 'wait-for-connection (list :jc jc :connection connection :initiator-jid initiator-jid :target-jid target-jid :streamhost-jid streamhost-jid :sid sid :socks5-fsm socks5-fsm) 30)) ;; So we open a stream, and wait for the connection to succeed. (condition-case nil (let ((connection (open-network-stream "socks5" nil host (string-to-number port)))) (set-process-filter connection (fsm-make-filter fsm)) (set-process-sentinel connection (fsm-make-sentinel fsm)) (list 'authenticate (list :jc jc :connection connection :initiator-jid initiator-jid :target-jid target-jid :streamhost-jid streamhost-jid :sid sid :socks5-fsm socks5-fsm) nil)) (error (list 'fail '() nil))))))) (define-state jabber-socks5-connection wait-for-connection (fsm state-data event callback) (cond ((eq (car-safe event) :sentinel) (let ((string (third event))) (cond ;; Connection succeeded ((string= (substring string 0 4) "open") (list 'authenticate state-data nil)) ;; Connection failed (t (list 'fail state-data nil))))))) (define-enter-state jabber-socks5-connection authenticate (fsm state-data) "Send authenticate command." ;; version: 5. number of auth methods supported: 1. ;; which one: no authentication. (process-send-string (plist-get state-data :connection) (string 5 1 0)) (list state-data 30)) (define-state jabber-socks5-connection authenticate (fsm state-data event callback) "Receive response to authenticate command." (cond ((eq (car-safe event) :filter) (let ((string (third event))) ;; should return: ;; version: 5. auth method to use: none (if (string= string (string 5 0)) ;; Authenticated. Send connect command. (list 'connect state-data nil) ;; Authentication failed... (delete-process (second event)) (list 'fail state-data nil)))) ((eq (car-safe event) :sentinel) (list 'fail state-data nil)))) (define-enter-state jabber-socks5-connection connect (fsm state-data) "Send connect command." (let* ((sid (plist-get state-data :sid)) (initiator (plist-get state-data :initiator-jid)) (target (plist-get state-data :target-jid)) (hash (sha1-string (concat sid initiator target)))) (process-send-string (plist-get state-data :connection) (concat (string 5 1 0 3 (length hash)) hash (string 0 0))) (list state-data 30))) (define-state jabber-socks5-connection connect (fsm state-data event callback) "Receive response to connect command." (cond ((eq (car-safe event) :filter) (let ((string (third event))) (if (string= (substring string 0 2) (string 5 0)) ;; connection established (progn (fsm-send (plist-get state-data :socks5-fsm) (list :connected (plist-get state-data :connection) (plist-get state-data :streamhost-jid))) ;; Our work is done (list 'done nil)) (list 'fail state-data nil)))) ((eq (car-safe event) :sentinel) (list 'fail state-data nil)))) (define-state jabber-socks5-connection done (fsm state-data event callback) ;; ignore all events (list 'done nil nil)) (define-enter-state jabber-socks5-connection fail (fsm state-data) ;; Notify parent fsm about failure (fsm-send (plist-get state-data :socks5-fsm) :not-connected) (list nil nil)) (define-state jabber-socks5-connection fail (fsm state-data event callback) ;; ignore all events (list 'fail nil nil)) (define-state jabber-socks5 wait-for-connection (fsm state-data event callback) (cond ((eq (car-safe event) :connected) (destructuring-bind (ignored connection streamhost-jid) event (setq state-data (plist-put state-data :connection connection)) ;; If we are expected to tell which streamhost we chose, do so. (let ((iq-id (plist-get state-data :iq-id))) (when iq-id (jabber-send-iq (plist-get state-data :jc) (plist-get state-data :jid) "result" `(query ((xmlns . "http://jabber.org/protocol/bytestreams")) (streamhost-used ((jid . ,streamhost-jid)))) nil nil nil nil iq-id))) ;; If we are the initiator, we should activate the bytestream. (if (eq (plist-get state-data :role) :initiator) (progn (jabber-send-iq (plist-get state-data :jc) streamhost-jid "set" `(query ((xmlns . "http://jabber.org/protocol/bytestreams") (sid . ,(plist-get state-data :sid))) (activate nil ,(plist-get state-data :jid))) (lambda (jc xml-data fsm) (fsm-send-sync fsm :activated)) fsm (lambda (jc xml-data fsm) (fsm-send-sync fsm :activation-failed)) fsm) (list 'wait-for-activation state-data 10)) ;; Otherwise, we just let the data flow. (list 'stream-activated state-data nil)))) ((eq event :not-connected) ;; If we were counting the streamhosts, we would know when there ;; are no more chances left. (list 'wait-for-connection state-data :keep)) ((eq event :timeout) (list 'fail (plist-put state-data :error "Timeout when connecting to streamhosts") nil)))) (define-state jabber-socks5 wait-for-activation (fsm state-data event callback) (cond ((eq event :activated) (list 'stream-activated state-data nil)) ((eq event :activation-failed) (list 'fail (plist-put state-data :error "Proxy activation failed") nil)) ;; Stray events from earlier state ((eq (car-safe event) :connected) ;; We just close the connection (delete-process (second event)) (list 'wait-for-activation state-data :keep)) ((eq event :not-connected) (list 'wait-for-activation state-data :keep)))) (define-enter-state jabber-socks5 stream-activated (fsm state-data) (let ((connection (plist-get state-data :connection)) (jc (plist-get state-data :jc)) (jid (plist-get state-data :jid)) (sid (plist-get state-data :sid)) (profile-function (plist-get state-data :profile-function))) (set-process-filter connection (fsm-make-filter fsm)) (set-process-sentinel connection (fsm-make-sentinel fsm)) ;; Call the profile function, passing the data send function, and ;; receiving the data receiving function. Put the data receiving ;; function in the plist. (list (plist-put state-data :profile-data-function (funcall profile-function jc jid sid (lexical-let ((fsm fsm)) (lambda (data) (fsm-send fsm (list :send data)))))) nil))) (define-state jabber-socks5 stream-activated (fsm state-data event callback) (let ((jc (plist-get state-data :jc)) (connection (plist-get state-data :connection)) (profile-data-function (plist-get state-data :profile-data-function)) (sid (plist-get state-data :sid)) (jid (plist-get state-data :jid))) (cond ((eq (car-safe event) :send) (process-send-string connection (second event)) (list 'stream-activated state-data nil)) ((eq (car-safe event) :filter) ;; Pass data from connection to profile data function ;; If the data function requests it, tear down the connection. (unless (funcall profile-data-function jc jid sid (third event)) (fsm-send fsm (list :sentinel (second event) "shutdown"))) (list 'stream-activated state-data nil)) ((eq (car-safe event) :sentinel) ;; Connection terminated. Shuffle together the remaining data, ;; and kill the buffer. (delete-process (second event)) (funcall profile-data-function jc jid sid nil) (list 'closed nil nil)) ;; Stray events from earlier state ((eq (car-safe event) :connected) ;; We just close the connection (delete-process (second event)) (list 'stream-activated state-data nil)) ((eq event :not-connected) (list 'stream-activated state-data nil))))) (define-enter-state jabber-socks5 fail (fsm state-data) "Tell our caller that we failed." (let ((jc (plist-get state-data :jc)) (jid (plist-get state-data :jid)) (sid (plist-get state-data :sid)) (profile-function (plist-get state-data :profile-function)) (iq-id (plist-get state-data :iq-id))) (funcall profile-function jc jid sid (plist-get state-data :error)) (when iq-id (jabber-send-iq-error jc jid iq-id nil "cancel" 'remote-server-not-found))) (list nil nil)) (defun jabber-socks5-client-1 (jc jid sid profile-function) "Negotiate a SOCKS5 connection with JID. This function simply starts a state machine." (add-to-list 'jabber-socks5-pending-sessions (list sid jid (start-jabber-socks5 jc jid sid profile-function :initiator)))) ;; (defun jabber-socks5-client-2 (xml-data jid sid profile-function) ;; "Contact has selected a streamhost to use. Connect to the proxy." ;; (let* ((query (jabber-iq-query xml-data)) ;; (streamhost-used (car (jabber-xml-get-children query 'streamhost-used))) ;; (proxy-used (jabber-xml-get-attribute streamhost-used 'jid)) ;; connection) ;; (let ((streamhosts-left (cdr (assoc proxy-used jabber-socks5-proxies-data)))) ;; (while (and streamhosts-left (not connection)) ;; (setq connection ;; (jabber-socks5-connect (car streamhosts-left) ;; sid ;; (concat jabber-username "@" jabber-server "/" jabber-resource) ;; jid)) ;; (setq streamhosts-left (cdr streamhosts-left)))) ;; (unless connection ;; (error "Couldn't connect to proxy %s" proxy-used)) ;; ;; Activation is only needed for proxies. ;; (jabber-send-iq proxy-used "set" ;; `(query ((xmlns . "http://jabber.org/protocol/bytestreams") ;; (sid . ,sid)) ;; (activate () ,jid)) ;; (lexical-let ((jid jid) (sid sid) (profile-function profile-function) ;; (connection connection)) ;; (lambda (xml-data closure-data) ;; (jabber-socks5-client-3 xml-data jid sid profile-function connection))) nil ;; ;; TODO: report error to contact? ;; #'jabber-report-success "Proxy activation"))) ;; (defun jabber-socks5-client-3 (xml-data jid sid profile-function proxy-connection) ;; "Proxy is activated. Start the transfer." ;; ;; The response from the proxy does not contain any interesting ;; ;; information, beyond success confirmation. ;; (funcall profile-function jid sid ;; (lexical-let ((proxy-connection proxy-connection)) ;; (lambda (data) ;; (process-send-string proxy-connection data))))) (provide 'jabber-socks5) ;;; arch-tag: 9e70dfea-2522-40c6-a79f-302c8fb82ac5 emacs-jabber-0.8.0/jabber-time.el0000644000175100017510000001141011133727374013465 00000000000000;; jabber-time.el - time reporting by JEP-0090 ;; Copyright (C) 2006 - Kirill A. Kroinskiy - catap@catap.ru ;; Copyright (C) 2006 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. (require 'jabber-iq) (require 'jabber-util) (require 'time-date) (add-to-list 'jabber-jid-info-menu (cons "Request time" 'jabber-get-time)) (defun jabber-get-time (jc to) "Request time" (interactive (list (jabber-read-account) (jabber-read-jid-completing "Request time of: " nil nil nil 'full))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:time"))) #'jabber-process-data #'jabber-process-time #'jabber-process-data "Time request failed")) ;; called by jabber-process-data (defun jabber-process-time (jc xml-data) "Handle results from jabber:iq:time requests." (let ((query (jabber-iq-query xml-data))) (let ((display (car (jabber-xml-node-children (car (jabber-xml-get-children query 'display))))) (utc (car (jabber-xml-node-children (car (jabber-xml-get-children query 'utc))))) (tz (car (jabber-xml-node-children (car (jabber-xml-get-children query 'tz)))))) (insert "Time:\t\t") (cond (display (insert display)) (utc (insert (format-time-string "%Y-%m-%d %T" (jabber-parse-legacy-time utc))))) (insert "\n") (when tz (insert "Time zone:\t" tz "\n"))))) ;; the only difference between these two functions is the ;; jabber-read-jid-completing call. (defun jabber-get-last-online (jc to) "Request time since a user was last online, or uptime of a component." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Get last online for: " nil nil nil 'bare-or-muc))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:last"))) #'jabber-process-data #'jabber-process-last #'jabber-process-data "Last online request failed")) (defun jabber-get-idle-time (jc to) "Request idle time of user." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Get idle time for: " nil nil nil 'full))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:last"))) #'jabber-process-data #'jabber-process-last #'jabber-process-data "Idle time request failed")) (defun jabber-process-last (jc xml-data) "Handle resultts from jabber:iq:last requests." (let* ((from (jabber-xml-get-attribute xml-data 'from)) (query (jabber-iq-query xml-data)) (seconds (jabber-xml-get-attribute query 'seconds)) (message (car (jabber-xml-node-children query)))) (cond ((jabber-jid-resource from) ;; Full JID: idle time (insert (format "Idle for %s seconds" seconds) "\n")) ((jabber-jid-username from) ;; Bare JID with username: time since online (insert (format "Last online %s seconds ago" seconds) "\n") (let ((seconds (condition-case nil (string-to-number seconds) (error nil)))) (when (numberp seconds) (insert "That is, at " (format-time-string "%Y-%m-%d %T" (time-subtract (current-time) (seconds-to-time seconds))) "\n")))) (t ;; Only hostname: uptime (insert (format "Uptime: %s seconds" seconds) "\n"))))) (add-to-list 'jabber-iq-get-xmlns-alist (cons "jabber:iq:time" 'jabber-return-time)) (add-to-list 'jabber-advertised-features "jabber:iq:time") (defun jabber-return-time (jc xml-data) "Return client time as defined in JEP-0090. Sender and ID are determined from the incoming packet passed in XML-DATA." (let ((to (jabber-xml-get-attribute xml-data 'from)) (id (jabber-xml-get-attribute xml-data 'id))) (jabber-send-iq jc to "result" `(query ((xmlns . "jabber:iq:time")) ;; what is ``human-readable'' format? ;; the same way as formating using by tkabber (display () ,(format-time-string "%a %b %d %H:%M:%S %Z %Y")) (tz () ,(format-time-string "%Z")) (utc () ,(jabber-encode-legacy-time nil))) nil nil nil nil id))) (provide 'jabber-time) ;; arch-tag: 5396bfda-323a-11db-ac8d-000a95c2fcd0 emacs-jabber-0.8.0/jabber-truncate.el0000644000175100017510000000453111133727374014362 00000000000000;; jabber-truncate.el - cleanup top lines in chatbuffers ;; Copyright (C) 2007 - Kirill A. Korinskiy - catap@catap.ru ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-chat) (eval-when-compile (require 'cl)) (defvar jabber-log-lines-to-keep 1000 "Maximum number of lines in chat buffer") (defun jabber-truncate-top () "Clean old history from a chat buffer. `jabber-log-lines-to-keep' specifies the number of lines to keep." (interactive) (let ((inhibit-read-only t) (delete-before ;; go back one node, to make this function "idempotent" (ewoc-prev jabber-chat-ewoc (ewoc-locate jabber-chat-ewoc (save-excursion (goto-char (point-max)) (forward-line (- jabber-log-lines-to-keep)) (point)))))) (while delete-before (setq delete-before (prog1 (ewoc-prev jabber-chat-ewoc delete-before) (ewoc-delete jabber-chat-ewoc delete-before)))))) (defun jabber-truncate-muc (nick group buffer text proposed-alert) "Clean old history from MUC buffers. `jabber-log-lines-to-keep' specifies the number of lines to keep." (jabber-truncate-top)) (defun jabber-truncate-chat (from buffer text proposed-alert) "Clean old history from chat buffers. `jabber-log-lines-to-keep' specifies the number of lines to keep. Note that this might interfer with `jabber-chat-display-more-backlog': you ask for more history, you get it, and then it just gets deleted." (jabber-truncate-top)) (pushnew 'jabber-truncate-muc (get 'jabber-alert-muc-hooks 'custom-options)) (pushnew 'jabber-truncate-chat (get 'jabber-alert-message-hooks 'custom-options)) (provide 'jabber-truncate) ;; arch-tag: 3d1e3428-f598-11db-a314-000a95c2fcd0 emacs-jabber-0.8.0/jabber-util.el0000644000175100017510000006176511250455045013517 00000000000000;; jabber-util.el - various utility functions -*- coding: utf-8; -*- ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; Copyright (C) 2008 - Terechkov Evgenii - evg@altlinux.org ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'cl)) (condition-case nil (require 'password) (error nil)) (defvar jabber-jid-history nil "History of entered JIDs") ;; Define `jabber-replace-in-string' somehow. (cond ;; Emacs 21 has replace-regexp-in-string. ((fboundp 'replace-regexp-in-string) (defsubst jabber-replace-in-string (str regexp newtext) (replace-regexp-in-string regexp newtext str t t))) ;; XEmacs has replace-in-string. However, color-theme defines it as ;; well on Emacs 2x, so this check must be last. ((fboundp 'replace-in-string) ;; And the version in color-theme takes only three arguments. Check ;; just to be sure. (condition-case nil (replace-in-string "foobar" "foo" "bar" t) (wrong-number-of-arguments (error "`replace-in-string' doesn't accept fourth argument"))) (defsubst jabber-replace-in-string (str regexp newtext) (replace-in-string str regexp newtext t))) (t (error "No implementation of `jabber-replace-in-string' available"))) ;;; XEmacs compatibility. Stolen from ibuffer.el (if (fboundp 'propertize) (defalias 'jabber-propertize 'propertize) (defun jabber-propertize (string &rest properties) "Return a copy of STRING with text properties added. [Note: this docstring has been copied from the Emacs 21 version] First argument is the string to copy. Remaining arguments form a sequence of PROPERTY VALUE pairs for text properties to add to the result." (let ((str (copy-sequence string))) (add-text-properties 0 (length str) properties str) str))) (unless (fboundp 'bound-and-true-p) (defmacro bound-and-true-p (var) "Return the value of symbol VAR if it is bound, else nil." `(and (boundp (quote ,var)) ,var))) ;;; more XEmacs compatibility ;;; Preserve input method when entering a minibuffer (if (featurep 'xemacs) ;; I don't know how to do this (defsubst jabber-read-with-input-method (prompt &optional initial-contents history default-value) (read-string prompt initial-contents history default-value)) (defsubst jabber-read-with-input-method (prompt &optional initial-contents history default-value) (read-string prompt initial-contents history default-value t))) (unless (fboundp 'delete-and-extract-region) (defsubst delete-and-extract-region (start end) (prog1 (buffer-substring start end) (delete-region start end)))) (unless (fboundp 'access-file) (defsubst access-file (filename error-message) (unless (file-readable-p filename) (error error-message)))) (if (fboundp 'float-time) (defalias 'jabber-float-time 'float-time) (defun jabber-float-time (&optional specified-time) (unless specified-time (setq specified-time (current-time))) ;; second precision is good enough for us (+ (* 65536.0 (car specified-time)) (cadr specified-time)))) (cond ((fboundp 'cancel-timer) (defalias 'jabber-cancel-timer 'cancel-timer)) ((fboundp 'delete-itimer) (defalias 'jabber-cancel-timer 'delete-itimer)) (t (error "No `cancel-timer' function found"))) (defun jabber-concat-rosters () "Concatenate the rosters of all connected accounts." (apply #'append (mapcar (lambda (jc) (plist-get (fsm-get-state-data jc) :roster)) jabber-connections))) (defun jabber-connection-jid (jc) "Return the full JID of the given connection." (let ((sd (fsm-get-state-data jc))) (concat (plist-get sd :username) "@" (plist-get sd :server) "/" (plist-get sd :resource)))) (defun jabber-connection-bare-jid (jc) "Return the bare JID of the given connection." (let ((sd (fsm-get-state-data jc))) (concat (plist-get sd :username) "@" (plist-get sd :server)))) (defun jabber-find-connection (bare-jid) "Find the connection to the account named by BARE-JID. Return nil if none found." (dolist (jc jabber-connections) (when (string= bare-jid (jabber-connection-bare-jid jc)) (return jc)))) (defun jabber-find-active-connection (dead-jc) "Given a dead connection, find an active connection to the same account. Return nil if none found." (let ((jid (jabber-connection-bare-jid dead-jc))) (jabber-find-connection jid))) (defun jabber-jid-username (string) "return the username portion of a JID, or nil if no username" (when (string-match "\\(.*\\)@.*\\(/.*\\)?" string) (match-string 1 string))) (defun jabber-jid-user (string) "return the user (username@server) portion of a JID" ;;transports don't have @, so don't require it ;;(string-match ".*@[^/]*" string) (string-match "[^/]*" string) (match-string 0 string)) (defun jabber-jid-server (string) "Return the server portion of a JID." (string-match "^\\(.*@\\)?\\([^@/]+\\)\\(/.*\\)?$" string) (match-string 2 string)) (defun jabber-jid-rostername (string) "return the name of the user, if given in roster, else nil" (let ((user (jabber-jid-symbol string))) (if (> (length (get user 'name)) 0) (get user 'name)))) (defun jabber-jid-displayname (string) "return the name of the user, if given in roster, else username@server" (or (jabber-jid-rostername string) (jabber-jid-user (if (symbolp string) (symbol-name string) string)))) (defun jabber-jid-resource (string) "return the resource portion of a JID, or nil if there is none." (when (string-match "^\\(\\([^/]*@\\)?[^/]*\\)/\\(.*\\)" string) (match-string 3 string))) (defun jabber-jid-symbol (string) "return the symbol for the given JID" ;; If it's already a symbol, just return it. (if (symbolp string) string ;; XXX: "downcase" is poor man's nodeprep. See XMPP CORE. (intern (downcase (jabber-jid-user string)) jabber-jid-obarray))) (defun jabber-my-jid-p (jc jid) "Return non-nil if the specified JID is in jabber-account-list (modulo resource). Also return non-nil if JID matches JC, modulo resource." (or (equal (jabber-jid-user jid) (jabber-connection-bare-jid jc)) (member (jabber-jid-user jid) (mapcar (lambda (x) (jabber-jid-user (car x))) jabber-account-list)))) (defun jabber-read-jid-completing (prompt &optional subset require-match default resource) "read a jid out of the current roster from the minibuffer. If SUBSET is non-nil, it should be a list of symbols from which the JID is to be selected, instead of using the entire roster. If REQUIRE-MATCH is non-nil, the JID must be in the list used. If DEFAULT is non-nil, it's used as the default value, otherwise the default is inferred from context. RESOURCE is one of the following: nil Accept full or bare JID, as entered full Turn bare JIDs to full ones with highest-priority resource bare-or-muc Turn full JIDs to bare ones, except for in MUC" (let ((jid-at-point (or (and default ;; default can be either a symbol or a string (if (symbolp default) (symbol-name default) default)) (get-text-property (point) 'jabber-jid) (bound-and-true-p jabber-chatting-with) (bound-and-true-p jabber-group))) (completion-ignore-case t) (jid-completion-table (mapcar #'(lambda (item) (cons (symbol-name item) item)) (or subset (jabber-concat-rosters)))) chosen) (dolist (item (or subset (jabber-concat-rosters))) (if (get item 'name) (push (cons (get item 'name) item) jid-completion-table))) ;; if the default is not in the allowed subset, it's not a good default (if (and subset (not (assoc jid-at-point jid-completion-table))) (setq jid-at-point nil)) (let ((input (completing-read (concat prompt (if jid-at-point (format "(default %s) " jid-at-point))) jid-completion-table nil require-match nil 'jabber-jid-history jid-at-point))) (setq chosen (if (and input (assoc-ignore-case input jid-completion-table)) (symbol-name (cdr (assoc-ignore-case input jid-completion-table))) (and (not (zerop (length input))) input)))) (when chosen (case resource (full ;; If JID is bare, add the highest-priority resource. (if (jabber-jid-resource chosen) chosen (let ((highest-resource (get (jabber-jid-symbol chosen) 'resource))) (if highest-resource (concat chosen "/" highest-resource) chosen)))) (bare-or-muc ;; If JID is full and non-MUC, remove resource. (if (null (jabber-jid-resource chosen)) chosen (let ((bare (jabber-jid-user chosen))) (if (assoc bare *jabber-active-groupchats*) chosen bare)))) (t chosen))))) (defun jabber-read-node (prompt) "Read node name, taking default from disco item at point." (let ((node-at-point (get-text-property (point) 'jabber-node))) (read-string (concat prompt (if node-at-point (format "(default %s) " node-at-point))) node-at-point))) (defun jabber-password-key (bare-jid) "Construct key for `password' library from BARE-JID." (concat "xmpp:" bare-jid)) (defun jabber-read-password (bare-jid) "Read Jabber password from minibuffer." (let ((prompt (format "Jabber password for %s: " bare-jid))) (if (require 'password-cache nil t) ;; Need to copy the password, as sasl.el wants to erase it. (copy-sequence (password-read prompt (jabber-password-key bare-jid))) (read-passwd prompt)))) (defun jabber-cache-password (bare-jid password) "Cache PASSWORD for BARE-JID." (when (fboundp 'password-cache-add) (password-cache-add (jabber-password-key bare-jid) password))) (defun jabber-uncache-password (bare-jid) "Uncache cached password for BARE-JID. Useful if the password proved to be wrong." (interactive (list (jabber-jid-user (completing-read "Forget password of account: " jabber-account-list nil nil nil 'jabber-account-history)))) (when (fboundp 'password-cache-remove) (password-cache-remove (jabber-password-key bare-jid)))) (defun jabber-read-account (&optional always-ask) "Ask for which connected account to use. If ALWAYS-ASK is nil and there is only one account, return that account." (let ((completions (mapcar (lambda (c) (cons (jabber-connection-bare-jid c) c)) jabber-connections))) (cond ((null jabber-connections) (error "Not connected to Jabber")) ((and (null (cdr jabber-connections)) (not always-ask)) ;; only one account (car jabber-connections)) (t (or ;; if there is a jabber-account property at point, ;; present it as default value (cdr (assoc (let ((at-point (get-text-property (point) 'jabber-account))) (when (and at-point (memq at-point jabber-connections)) (jabber-connection-bare-jid at-point))) completions)) (let* ((default (or ;; if the buffer is associated with a connection, use it (when (and jabber-buffer-connection (memq jabber-buffer-connection jabber-connections)) (jabber-connection-bare-jid jabber-buffer-connection)) ;; else, use the first connection in the list (caar completions))) (input (completing-read (concat "Select Jabber account (default " default "): ") completions nil t nil 'jabber-account-history default))) (cdr (assoc input completions)))))))) (defun jabber-iq-query (xml-data) "Return the query part of an IQ stanza. An IQ stanza may have zero or one query child, and zero or one child. The query child is often but not always ." (let (query) (dolist (x (jabber-xml-node-children xml-data)) (if (and (listp x) (not (eq (jabber-xml-node-name x) 'error))) (setq query x))) query)) (defun jabber-iq-error (xml-data) "Return the part of an IQ stanza, if any." (car (jabber-xml-get-children xml-data 'error))) (defun jabber-iq-xmlns (xml-data) "Return the namespace of an IQ stanza, i.e. the namespace of its query part." (jabber-xml-get-attribute (jabber-iq-query xml-data) 'xmlns)) (defun jabber-x-delay (xml-data) "Return timestamp given a tag in namespace jabber:x:delay. Return nil if no such data available." (when (and (eq (jabber-xml-node-name xml-data) 'x) (string= (jabber-xml-get-attribute xml-data 'xmlns) "jabber:x:delay")) (let ((stamp (jabber-xml-get-attribute xml-data 'stamp))) (if (and (stringp stamp) (= (length stamp) 17)) (jabber-parse-legacy-time stamp))))) (defun jabber-parse-legacy-time (timestamp) "Parse timestamp in ccyymmddThh:mm:ss format (UTC) and return as internal time value." (let ((year (string-to-number (substring timestamp 0 4))) (month (string-to-number (substring timestamp 4 6))) (day (string-to-number (substring timestamp 6 8))) (hour (string-to-number (substring timestamp 9 11))) (minute (string-to-number (substring timestamp 12 14))) (second (string-to-number (substring timestamp 15 17)))) (encode-time second minute hour day month year 0))) (defun jabber-encode-legacy-time (timestamp) "Parse TIMESTAMP as internal time value and encode as ccyymmddThh:mm:ss (UTC)." (if (featurep 'xemacs) ;; XEmacs doesn't have `universal' argument to format-time-string, ;; so we have to do it ourselves. (format-time-string "%Y%m%dT%H:%M:%S" (time-subtract timestamp (list 0 (car (current-time-zone))))) (format-time-string "%Y%m%dT%H:%M:%S" timestamp t))) (defun jabber-encode-time (time) "Convert TIME to a string by JEP-0082. TIME is in a format accepted by `format-time-string'." (let ((time-zone-offset (nth 0 (current-time-zone)))) (if (null time-zone-offset) ;; no time zone information available; pretend it's UTC (format-time-string "%Y-%m-%dT%H:%M:%SZ" time) (let* ((positivep (>= time-zone-offset 0)) (hours (/ (abs time-zone-offset) 3600)) (minutes (/ (% (abs time-zone-offset) 3600) 60))) (format "%s%s%02d:%02d" (format-time-string "%Y-%m-%dT%H:%M:%S" time) (if positivep "+" "-") hours minutes))))) (defun jabber-parse-time (time) "Parse the DateTime encoded in TIME according to JEP-0082." (let* ((year (string-to-number (substring time 0 4))) (month (string-to-number (substring time 5 7))) (day (string-to-number (substring time 8 10))) (hour (string-to-number (substring time 11 13))) (minute (string-to-number (substring time 14 16))) (second (string-to-number (substring time 17 19))) ;; fractions are optional (fraction (if (eq (aref time 19) ?.) (string-to-number (substring time 20 23)))) (timezone (substring time (if fraction 23 19)))) ;; timezone is either Z (UTC) or [+-]HH:MM (let ((timezone-seconds (if (string= timezone "Z") 0 (* (if (eq (aref timezone 0) ?+) 1 -1) (* 60 (+ (* 60 (string-to-number (substring timezone 1 3))) (string-to-number (substring timezone 4 6)))))))) (encode-time second minute hour day month year timezone-seconds)))) (defun jabber-report-success (jc xml-data context) "IQ callback reporting success or failure of the operation. CONTEXT is a string describing the action. \"CONTEXT succeeded\" or \"CONTEXT failed: REASON\" is displayed in the echo area." (let ((type (jabber-xml-get-attribute xml-data 'type))) (message (concat context (if (string= type "result") " succeeded" (concat " failed: " (let ((the-error (jabber-iq-error xml-data))) (if the-error (jabber-parse-error the-error) "No error message given")))))))) (defconst jabber-error-messages (list (cons 'bad-request "Bad request") (cons 'conflict "Conflict") (cons 'feature-not-implemented "Feature not implemented") (cons 'forbidden "Forbidden") (cons 'gone "Gone") (cons 'internal-server-error "Internal server error") (cons 'item-not-found "Item not found") (cons 'jid-malformed "JID malformed") (cons 'not-acceptable "Not acceptable") (cons 'not-allowed "Not allowed") (cons 'not-authorized "Not authorized") (cons 'payment-required "Payment required") (cons 'recipient-unavailable "Recipient unavailable") (cons 'redirect "Redirect") (cons 'registration-required "Registration required") (cons 'remote-server-not-found "Remote server not found") (cons 'remote-server-timeout "Remote server timeout") (cons 'resource-constraint "Resource constraint") (cons 'service-unavailable "Service unavailable") (cons 'subscription-required "Subscription required") (cons 'undefined-condition "Undefined condition") (cons 'unexpected-request "Unexpected request")) "String descriptions of XMPP stanza errors") (defconst jabber-legacy-error-messages (list (cons 302 "Redirect") (cons 400 "Bad request") (cons 401 "Unauthorized") (cons 402 "Payment required") (cons 403 "Forbidden") (cons 404 "Not found") (cons 405 "Not allowed") (cons 406 "Not acceptable") (cons 407 "Registration required") (cons 408 "Request timeout") (cons 409 "Conflict") (cons 500 "Internal server error") (cons 501 "Not implemented") (cons 502 "Remote server error") (cons 503 "Service unavailable") (cons 504 "Remote server timeout") (cons 510 "Disconnected")) "String descriptions of legacy errors (JEP-0086)") (defun jabber-parse-error (error-xml) "Parse the given tag and return a string fit for human consumption. See secton 9.3, Stanza Errors, of XMPP Core, and JEP-0086, Legacy Errors." (let ((error-type (jabber-xml-get-attribute error-xml 'type)) (error-code (jabber-xml-get-attribute error-xml 'code)) condition text) (if error-type ;; If the tag has a type element, it is new-school. (dolist (child (jabber-xml-node-children error-xml)) (when (string= (jabber-xml-get-attribute child 'xmlns) "urn:ietf:params:xml:ns:xmpp-stanzas") (if (eq (jabber-xml-node-name child) 'text) (setq text (car (jabber-xml-node-children child))) (setq condition (or (cdr (assq (jabber-xml-node-name child) jabber-error-messages)) (symbol-name (jabber-xml-node-name child))))))) (setq condition (or (cdr (assq (string-to-number error-code) jabber-legacy-error-messages)) error-code)) (setq text (car (jabber-xml-node-children error-xml)))) (concat condition (if text (format ": %s" text))))) (defun jabber-error-condition (error-xml) "Parse the given tag and return the condition symbol." (catch 'condition (dolist (child (jabber-xml-node-children error-xml)) (when (string= (jabber-xml-get-attribute child 'xmlns) "urn:ietf:params:xml:ns:xmpp-stanzas") (throw 'condition (jabber-xml-node-name child)))))) (defvar jabber-stream-error-messages (list (cons 'bad-format "Bad XML format") (cons 'bad-namespace-prefix "Bad namespace prefix") (cons 'conflict "Conflict") (cons 'connection-timeout "Connection timeout") (cons 'host-gone "Host gone") (cons 'host-unknown "Host unknown") (cons 'improper-addressing "Improper addressing") ; actually only s2s (cons 'internal-server-error "Internal server error") (cons 'invalid-from "Invalid from") (cons 'invalid-id "Invalid id") (cons 'invalid-namespace "Invalid namespace") (cons 'invalid-xml "Invalid XML") (cons 'not-authorized "Not authorized") (cons 'policy-violation "Policy violation") (cons 'remote-connection-failed "Remote connection failed") (cons 'resource-constraint "Resource constraint") (cons 'restricted-xml "Restricted XML") (cons 'see-other-host "See other host") (cons 'system-shutdown "System shutdown") (cons 'undefined-condition "Undefined condition") (cons 'unsupported-encoding "Unsupported encoding") (cons 'unsupported-stanza-type "Unsupported stanza type") (cons 'unsupported-version "Unsupported version") (cons 'xml-not-well-formed "XML not well formed")) "String descriptions of XMPP stream errors") (defun jabber-stream-error-condition (error-xml) "Return the condition of a tag." ;; as we don't know the node name of the condition, we have to ;; search for it. (dolist (node (jabber-xml-node-children error-xml)) (when (and (string= (jabber-xml-get-attribute node 'xmlns) "urn:ietf:params:xml:ns:xmpp-streams") (assq (jabber-xml-node-name node) jabber-stream-error-messages)) (return (jabber-xml-node-name node))))) (defun jabber-parse-stream-error (error-xml) "Parse the given tag and return a sting fit for human consumption." (let ((text-node (car (jabber-xml-get-children error-xml 'text))) (condition (jabber-stream-error-condition error-xml))) (concat (if condition (cdr (assq condition jabber-stream-error-messages)) "Unknown stream error") (if (and text-node (stringp (car (jabber-xml-node-children text-node)))) (concat ": " (car (jabber-xml-node-children text-node))))))) (put 'jabber-error 'error-conditions '(error jabber-error)) (put 'jabber-error 'error-message "Jabber error") (defun jabber-signal-error (error-type condition &optional text app-specific) "Signal an error to be sent by Jabber. ERROR-TYPE is one of \"cancel\", \"continue\", \"modify\", \"auth\" and \"wait\". CONDITION is a symbol denoting a defined XMPP condition. TEXT is a string to be sent in the error message, or nil for no text. APP-SPECIFIC is a list of extra XML tags. See section 9.3 of XMPP Core." (signal 'jabber-error (list error-type condition text app-specific))) (defun jabber-unhex (string) "Convert a hex-encoded UTF-8 string to Emacs representation. For example, \"ji%C5%99i@%C4%8Dechy.example/v%20Praze\" becomes \"jiři@čechy.example/v Praze\"." (decode-coding-string (url-unhex-string string) 'utf-8)) (defun jabber-handle-uri (uri &rest ignored-args) "Handle XMPP links according to draft-saintandre-xmpp-iri-04. See Info node `(jabber)XMPP URIs'." (interactive "sEnter XMPP URI: ") (when (string-match "//" uri) (error "URIs with authority part are not supported")) ;; This regexp handles three cases: ;; xmpp:romeo@montague.net ;; xmpp:romeo@montague.net?roster ;; xmpp:romeo@montague.net?roster;name=Romeo%20Montague;group=Lovers (unless (string-match "^xmpp:\\([^?]+\\)\\(\\?\\([a-z]+\\)\\(;\\(.*\\)\\)?\\)?" uri) (error "Invalid XMPP URI '%s'" uri)) ;; We start by raising the Emacs frame. (raise-frame) (let ((jid (jabber-unhex (match-string 1 uri))) (method (match-string 3 uri)) (args (let ((text (match-string 5 uri))) ;; If there are arguments... (when text ;; ...split the pairs by ';'... (let ((pairs (split-string text ";"))) (mapcar (lambda (pair) ;; ...and split keys from values by '='. (destructuring-bind (key value) (split-string pair "=") ;; Values can be hex-coded. (cons key (jabber-unhex value)))) pairs)))))) ;; The full list of methods is at ;; . (cond ;; Join an MUC. ((string= method "join") (let ((account (jabber-read-account))) (jabber-groupchat-join account jid (jabber-muc-read-my-nickname account jid) t))) ;; Register with a service. ((string= method "register") (jabber-get-register (jabber-read-account) jid)) ;; Run an ad-hoc command ((string= method "command") ;; XXX: does the 'action' attribute make sense? (jabber-ahc-execute-command (jabber-read-account) jid (cdr (assoc "node" args)))) ;; Everything else: open a chat buffer. (t (jabber-chat-with (jabber-read-account) jid))))) (defun url-xmpp (url) "Handle XMPP URLs from internal Emacs functions." ;; XXX: This parsing roundtrip is redundant, and the parser of the ;; url package might lose information. (jabber-handle-uri (url-recreate-url url))) (defun string>-numerical (s1 s2) "Return t if first arg string is more than second in numerical order." (cond ((string= s1 s2) nil) ((> (length s1) (length s2)) t) ((< (length s1) (length s2)) nil) ((< (string-to-number (substring s1 0 1)) (string-to-number (substring s2 0 1))) nil) ((> (string-to-number (substring s1 0 1)) (string-to-number (substring s2 0 1))) t) (t (string>-numerical (substring s1 1) (substring s2 1))))) (provide 'jabber-util) ;;; arch-tag: cfbb73ac-e2d7-4652-a08d-dc789bcded8a emacs-jabber-0.8.0/jabber-vcard-avatars.el0000644000175100017510000001156311133727374015276 00000000000000;;; jabber-vcard-avatars.el --- Avatars by JEP-0153 ;; Copyright (C) 2006, 2007, 2008 Magnus Henoch ;; Author: Magnus Henoch ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; ;;; Code: (require 'jabber-avatar) (defcustom jabber-vcard-avatars-retrieve (and (fboundp 'display-images-p) (display-images-p)) "Automatically download vCard avatars?" :group 'jabber-avatar :type 'boolean) (defcustom jabber-vcard-avatars-publish t "Publish your vCard photo as avatar?" :group 'jabber-avatar :type 'boolean) (defvar jabber-vcard-avatars-current-hash (make-hash-table :test 'equal) "For each connection, SHA1 hash of current avatar. Keys are full JIDs.") (add-to-list 'jabber-presence-chain 'jabber-vcard-avatars-presence) (defun jabber-vcard-avatars-presence (jc xml-data) "Look for vCard avatar mark in stanza." ;; Only look at ordinary presence (when (and jabber-vcard-avatars-retrieve (null (jabber-xml-get-attribute xml-data 'type))) (let* ((from (jabber-jid-user (jabber-xml-get-attribute xml-data 'from))) (photo (jabber-xml-path xml-data '(("vcard-temp:x:update" . "x") photo))) (sha1-hash (car (jabber-xml-node-children photo)))) (cond ((null sha1-hash) ;; User has removed avatar (jabber-avatar-set from nil)) ((string= sha1-hash (get (jabber-jid-symbol from) 'avatar-hash)) ;; Same avatar as before; do nothing ) ((jabber-avatar-find-cached sha1-hash) ;; Avatar is cached (jabber-avatar-set from sha1-hash)) (t ;; Avatar is not cached; retrieve it (jabber-vcard-avatars-fetch jc from sha1-hash)))))) (defun jabber-vcard-avatars-fetch (jc who sha1-hash) "Fetch WHO's vCard, and extract avatar." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Fetch whose vCard avatar: ") nil)) (jabber-send-iq jc who "get" '(vCard ((xmlns . "vcard-temp"))) #'jabber-vcard-avatars-vcard (cons who sha1-hash) #'ignore nil)) (defun jabber-vcard-avatars-vcard (jc iq closure) "Get the photo from the vCard, and set the avatar." (let ((from (car closure)) (sha1-hash (cdr closure)) (photo (assq 'PHOTO (jabber-vcard-parse (jabber-iq-query iq))))) (if photo (let ((avatar (jabber-avatar-from-base64-string (nth 2 photo) (nth 1 photo)))) (unless (or (null sha1-hash) (string= sha1-hash (avatar-sha1-sum avatar))) (when jabber-avatar-verbose (message "%s's avatar should have SHA1 sum %s, but has %s" (jabber-jid-displayname from) sha1-hash (avatar-sha1-sum avatar)))) (jabber-avatar-cache avatar) (jabber-avatar-set from avatar)) (jabber-avatar-set from nil)))) (defun jabber-vcard-avatars-find-current (jc) "Request our own vCard, to find hash of avatar." (when jabber-vcard-avatars-publish (jabber-send-iq jc nil "get" '(vCard ((xmlns . "vcard-temp"))) #'jabber-vcard-avatars-find-current-1 t #'jabber-vcard-avatars-find-current-1 nil))) (defun jabber-vcard-avatars-find-current-1 (jc xml-data success) (jabber-vcard-avatars-update-current jc (and success (let ((photo (assq 'PHOTO (jabber-vcard-parse (jabber-iq-query xml-data))))) (when photo (let ((avatar (jabber-avatar-from-base64-string (nth 2 photo) (nth 1 photo)))) (avatar-sha1-sum avatar))))))) (defun jabber-vcard-avatars-update-current (jc new-hash) (let ((old-hash (gethash (jabber-connection-bare-jid jc) jabber-vcard-avatars-current-hash))) (when (not (string= old-hash new-hash)) (puthash (jabber-connection-bare-jid jc) new-hash jabber-vcard-avatars-current-hash) (jabber-send-current-presence jc)))) (add-to-list 'jabber-presence-element-functions 'jabber-vcard-avatars-presence-element) (defun jabber-vcard-avatars-presence-element (jc) (when jabber-vcard-avatars-publish (let ((hash (gethash (jabber-connection-bare-jid jc) jabber-vcard-avatars-current-hash))) (list `(x ((xmlns . "vcard-temp:x:update")) ;; if "not yet ready to advertise image", don't. ;; that is, we haven't yet checked what avatar we have. ,(when hash `(photo () ,hash))))))) (provide 'jabber-vcard-avatars) ;; arch-tag: 3e50d460-8eae-11da-826c-000a95c2fcd0 emacs-jabber-0.8.0/jabber-vcard.el0000644000175100017510000004355711133727374013647 00000000000000;;; jabber-vcard.el --- vcards according to JEP-0054 ;; Copyright (C) 2005, 2007 Magnus Henoch ;; Author: Magnus Henoch ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; There are great variations in Jabber vcard implementations. This ;; one adds some spice to the mix, while trying to follow the JEP ;; closely. ;; Fields not implemented: GEO, LOGO, AGENT, ORG, CATEGORIES, SOUND, ;; CLASS, KEY. ;; The internal data structure used for vCards is an alist. All ;; keys are uppercase symbols. ;; ;; FN, NICKNAME, BDAY, JABBERID, MAILER, TZ, TITLE, ROLE, NOTE, ;; PRODID, REV, SORT-STRING, UID, URL, DESC: ;; Value is a string. ;; ;; N: ;; Value is an alist, with keys FAMILY, GIVEN, MIDDLE, PREFIX and SUFFIX. ;; ;; ADR: ;; Value is a list, each element representing a separate address. ;; The car of each address is a list of types; possible values are ;; HOME, WORK, POSTAL, PARCEL, DOM, INTL, PREF. ;; The cdr of each address is an alist, with keys POBOX, EXTADD, ;; STREET, LOCALITY, REGION, PCODE, CTRY, and values being strings. ;; ;; TEL: ;; Value is a list, each element representing a separate phone number. ;; The car of each number is a list of types; possible values are ;; HOME, WORK, VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, ;; PCS, PREF ;; The cdr is the phone number as a string. ;; ;; EMAIL: ;; Value is a list, each element representing a separate e-mail address. ;; The car of each address is a list of types; possible values are ;; HOME, WORK, INTERNET, PREF, X400. At least one of INTERNET and ;; X400 is always present. ;; The cdr is the address as a string. ;;; Code: (require 'jabber-core) (require 'jabber-widget) (require 'jabber-iq) (require 'jabber-avatar) (defvar jabber-vcard-photo nil "The avatar structure for the photo in the vCard edit buffer.") (make-variable-buffer-local 'jabber-vcard-photo) (defun jabber-vcard-parse (vcard) "Parse the vCard XML structure given in VCARD. The top node should be the `vCard' node." ;; Hm... stpeter has a as top node... ;;(unless (eq (jabber-xml-node-name vcard) 'vCard) ;; (error "Invalid vCard")) (let (result) (dolist (verbatim-node '(FN NICKNAME BDAY JABBERID MAILER TZ TITLE ROLE NOTE PRODID REV SORT-STRING UID URL DESC)) ;; There should only be one of each of these. They are ;; used verbatim. (let ((node (car (jabber-xml-get-children vcard verbatim-node)))) ;; Some clients include the node, but without data (when (car (jabber-xml-node-children node)) (push (cons (jabber-xml-node-name node) (car (jabber-xml-node-children node))) result)))) ;; Name components (let ((node (car (jabber-xml-get-children vcard 'N)))) ;; Subnodes are FAMILY, GIVEN, MIDDLE, PREFIX, SUFFIX (push (cons 'N (let (name) (dolist (subnode (jabber-xml-node-children node)) (when (and (memq (jabber-xml-node-name subnode) '(FAMILY GIVEN MIDDLE PREFIX SUFFIX)) (not (zerop (length (car (jabber-xml-node-children subnode)))))) (push (cons (jabber-xml-node-name subnode) (car (jabber-xml-node-children subnode))) name))) name)) result)) ;; There can be several addresses (let (addresses) (dolist (adr (jabber-xml-get-children vcard 'ADR)) ;; Find address type(s) (let (types) (dolist (possible-type '(HOME WORK POSTAL PARCEL DOM INTL PREF)) (when (jabber-xml-get-children adr possible-type) (push possible-type types))) (let (components) (dolist (component (jabber-xml-node-children adr)) (when (and (memq (jabber-xml-node-name component) '(POBOX EXTADD STREET LOCALITY REGION PCODE CTRY)) (not (zerop (length (car (jabber-xml-node-children component)))))) (push (cons (jabber-xml-node-name component) (car (jabber-xml-node-children component))) components))) (push (cons types components) addresses)))) (when addresses (push (cons 'ADR addresses) result))) ;; Likewise for phone numbers (let (phone-numbers) (dolist (tel (jabber-xml-get-children vcard 'TEL)) ;; Find phone type(s) (let ((number (car (jabber-xml-node-children (car (jabber-xml-get-children tel 'NUMBER))))) types) ;; Some clients put no NUMBER node. Avoid that. (when number (dolist (possible-type '(HOME WORK VOICE FAX PAGER MSG CELL VIDEO BBS MODEM ISDN PCS PREF)) (when (jabber-xml-get-children tel possible-type) (push possible-type types))) (push (cons types number) phone-numbers)))) (when phone-numbers (push (cons 'TEL phone-numbers) result))) ;; And for e-mail addresses (let (e-mails) (dolist (email (jabber-xml-get-children vcard 'EMAIL)) (let ((userid (car (jabber-xml-node-children (car (jabber-xml-get-children email 'USERID))))) types) ;; Some clients put no USERID node. Avoid that. (when userid (dolist (possible-type '(HOME WORK INTERNET PREF X400)) (when (jabber-xml-get-children email possible-type) (push possible-type types))) (unless (or (memq 'INTERNET types) (memq 'X400 types)) (push 'INTERNET types)) (push (cons types userid) e-mails)))) (when e-mails (push (cons 'EMAIL e-mails) result))) ;; JEP-0153: vCard-based avatars (let ((photo-tag (car (jabber-xml-get-children vcard 'PHOTO)))) (when photo-tag (let ((type (jabber-xml-path photo-tag '(TYPE ""))) (binval (jabber-xml-path photo-tag '(BINVAL "")))) (when (and type binval) (push (list 'PHOTO type binval) result))))) result)) (defun jabber-vcard-reassemble (parsed) "Create a vCard XML structure from PARSED." ;; Save photo in jabber-vcard-photo, to avoid excessive processing. (let ((photo (cdr (assq 'PHOTO parsed)))) (cond ;; No photo ((null photo) (setq jabber-vcard-photo nil)) ;; Existing photo ((listp photo) (setq jabber-vcard-photo (jabber-avatar-from-base64-string (nth 1 photo) (nth 0 photo)))) ;; New photo from file (t (access-file photo "Avatar file not found") ;; Maximum allowed size is 8 kilobytes (when (> (nth 7 (file-attributes photo)) 8192) (error "Avatar bigger than 8 kilobytes")) (setq jabber-vcard-photo (jabber-avatar-from-file photo))))) `(vCard ((xmlns . "vcard-temp")) ;; Put in simple fields ,@(mapcar (lambda (field) (when (and (assq (car field) jabber-vcard-fields) (not (zerop (length (cdr field))))) (list (car field) nil (cdr field)))) parsed) ;; Put in decomposited name (N nil ,@(mapcar (lambda (name-part) (when (not (zerop (length (cdr name-part)))) (list (car name-part) nil (cdr name-part)))) (cdr (assq 'N parsed)))) ;; Put in addresses ,@(mapcar (lambda (address) (append '(ADR) '(()) (mapcar 'list (nth 0 address)) (mapcar (lambda (field) (list (car field) nil (cdr field))) (cdr address)))) (cdr (assq 'ADR parsed))) ;; Put in phone numbers ,@(mapcar (lambda (phone) (append '(TEL) '(()) (mapcar 'list (car phone)) (list (list 'NUMBER nil (cdr phone))))) (cdr (assq 'TEL parsed))) ;; Put in e-mail addresses ,@(mapcar (lambda (email) (append '(EMAIL) '(()) (mapcar 'list (car email)) (list (list 'USERID nil (cdr email))))) (cdr (assq 'EMAIL parsed))) ;; Put in photo ,@(when jabber-vcard-photo `((PHOTO () (TYPE () ,(avatar-mime-type jabber-vcard-photo)) (BINVAL () ,(avatar-base64-data jabber-vcard-photo))))))) (add-to-list 'jabber-jid-info-menu (cons "Request vcard" 'jabber-vcard-get)) (defun jabber-vcard-get (jc jid) "Request vcard from JID." (interactive (list (jabber-read-account) (jabber-read-jid-completing "Request vcard from: " nil nil nil 'bare-or-muc))) (jabber-send-iq jc jid "get" '(vCard ((xmlns . "vcard-temp"))) #'jabber-process-data #'jabber-vcard-display #'jabber-process-data "Vcard request failed")) (defun jabber-vcard-edit (jc) "Edit your own vcard." (interactive (list (jabber-read-account))) (jabber-send-iq jc nil "get" '(vCard ((xmlns . "vcard-temp"))) #'jabber-vcard-do-edit nil #'jabber-report-success "Vcard request failed")) (defconst jabber-vcard-fields '((FN . "Full name") (NICKNAME . "Nickname") (BDAY . "Birthday") (URL . "URL") (JABBERID . "JID") (MAILER . "User agent") (TZ . "Time zone") (TITLE . "Title") (ROLE . "Role") (REV . "Last changed") (DESC . "Description") (NOTE . "Note"))) (defconst jabber-vcard-name-fields '((PREFIX . "Prefix") (GIVEN . "Given name") (MIDDLE . "Middle name") (FAMILY . "Family name") (SUFFIX . "Suffix"))) (defconst jabber-vcard-phone-types '((HOME . "Home") (WORK . "Work") (VOICE . "Voice") (FAX . "Fax") (PAGER . "Pager") (MSG . "Message") (CELL . "Cell phone") (VIDEO . "Video") (BBS . "BBS") (MODEM . "Modem") (ISDN . "ISDN") (PCS . "PCS"))) (defconst jabber-vcard-email-types '((HOME . "Home") (WORK . "Work") (INTERNET . "Internet") (X400 . "X400") (PREF . "Preferred"))) (defconst jabber-vcard-address-types '((HOME . "Home") (WORK . "Work") (POSTAL . "Postal") (PARCEL . "Parcel") (DOM . "Domestic") (INTL . "International") (PREF . "Preferred"))) (defconst jabber-vcard-address-fields '((POBOX . "Post box") (EXTADD . "Ext. address") (STREET . "Street") (LOCALITY . "Locality") (REGION . "Region") (PCODE . "Post code") (CTRY . "Country"))) (defun jabber-vcard-display (jc xml-data) "Display received vcard." (let ((parsed (jabber-vcard-parse (jabber-iq-query xml-data)))) (dolist (simple-field jabber-vcard-fields) (let ((field (assq (car simple-field) parsed))) (when field (insert (cdr simple-field)) (indent-to 20) (insert (cdr field) "\n")))) (let ((names (cdr (assq 'N parsed)))) (when names (insert "\n") (dolist (name-field jabber-vcard-name-fields) (let ((field (assq (car name-field) names))) (when field (insert (cdr name-field)) (indent-to 20) (insert (cdr field) "\n")))))) (let ((email-addresses (cdr (assq 'EMAIL parsed)))) (when email-addresses (insert "\n") (insert (jabber-propertize "E-mail addresses:\n" 'face 'jabber-title-medium)) (dolist (email email-addresses) (insert (mapconcat (lambda (type) (cdr (assq type jabber-vcard-email-types))) (car email) " ")) (insert ": " (cdr email) "\n")))) (let ((phone-numbers (cdr (assq 'TEL parsed)))) (when phone-numbers (insert "\n") (insert (jabber-propertize "Phone numbers:\n" 'face 'jabber-title-medium)) (dolist (number phone-numbers) (insert (mapconcat (lambda (type) (cdr (assq type jabber-vcard-phone-types))) (car number) " ")) (insert ": " (cdr number) "\n")))) (let ((addresses (cdr (assq 'ADR parsed)))) (when addresses (insert "\n") (insert (jabber-propertize "Addresses:\n" 'face 'jabber-title-medium)) (dolist (address addresses) (insert (jabber-propertize (mapconcat (lambda (type) (cdr (assq type jabber-vcard-address-types))) (car address) " ") 'face 'jabber-title-small)) (insert "\n") (dolist (address-field jabber-vcard-address-fields) (let ((field (assq (car address-field) address))) (when field (insert (cdr address-field)) (indent-to 20) (insert (cdr field) "\n"))))))) ;; JEP-0153: vCard-based avatars (let ((photo-type (nth 1 (assq 'PHOTO parsed))) (photo-binval (nth 2 (assq 'PHOTO parsed)))) (when (and photo-type photo-binval) (condition-case nil ;; ignore the type, let create-image figure it out. (let ((image (create-image (base64-decode-string photo-binval) nil t))) (insert-image image "[Photo]") (insert "\n")) (error (insert "Couldn't display photo\n"))))))) (defun jabber-vcard-do-edit (jc xml-data closure-data) (let ((parsed (jabber-vcard-parse (jabber-iq-query xml-data))) start-position) (with-current-buffer (get-buffer-create "Edit vcard") (jabber-init-widget-buffer nil) (setq jabber-buffer-connection jc) (setq start-position (point)) (dolist (simple-field jabber-vcard-fields) (widget-insert (cdr simple-field)) (indent-to 15) (let ((default-value (cdr (assq (car simple-field) parsed)))) (push (cons (car simple-field) (widget-create 'editable-field (or default-value ""))) jabber-widget-alist))) (widget-insert "\n") (push (cons 'N (widget-create '(set :tag "Decomposited name" (cons :tag "Prefix" :format "%t: %v" (const :format "" PREFIX) (string :format "%v")) (cons :tag "Given name" :format "%t: %v" (const :format "" GIVEN) (string :format "%v")) (cons :tag "Middle name" :format "%t: %v" (const :format "" MIDDLE) (string :format "%v")) (cons :tag "Family name" :format "%t: %v" (const :format "" FAMILY) (string :format "%v")) (cons :tag "Suffix" :format "%t: %v" (const :format "" SUFFIX) (string :format "%v"))) :value (cdr (assq 'N parsed)))) jabber-widget-alist) (widget-insert "\n") (push (cons 'ADR (widget-create '(repeat :tag "Postal addresses" (cons :tag "Address" (set :tag "Type" (const :tag "Home" HOME) (const :tag "Work" WORK) (const :tag "Postal" POSTAL) (const :tag "Parcel" PARCEL) (const :tag "Domestic" DOM) (const :tag "International" INTL) (const :tag "Preferred" PREF)) (set :tag "Address" (cons :tag "Post box" :format "%t: %v" (const :format "" POBOX) (string :format "%v")) (cons :tag "Ext. address" :format "%t: %v" (const :format "" EXTADD) (string :format "%v")) (cons :tag "Street" :format "%t: %v" (const :format "" STREET) (string :format "%v")) (cons :tag "Locality" :format "%t: %v" (const :format "" LOCALITY) (string :format "%v")) (cons :tag "Region" :format "%t: %v" (const :format "" REGION) (string :format "%v")) (cons :tag "Post code" :format "%t: %v" (const :format "" PCODE) (string :format "%v")) (cons :tag "Country" :format "%t: %v" (const :format "" CTRY) (string :format "%v"))))) :value (cdr (assq 'ADR parsed)))) jabber-widget-alist) (widget-insert "\n") (push (cons 'TEL (widget-create '(repeat :tag "Phone numbers" (cons :tag "Number" (set :tag "Type" (const :tag "Home" HOME) (const :tag "Work" WORK) (const :tag "Voice" VOICE) (const :tag "Fax" FAX) (const :tag "Pager" PAGER) (const :tag "Message" MSG) (const :tag "Cell phone" CELL) (const :tag "Video" VIDEO) (const :tag "BBS" BBS) (const :tag "Modem" MODEM) (const :tag "ISDN" ISDN) (const :tag "PCS" PCS)) (string :tag "Number"))) :value (cdr (assq 'TEL parsed)))) jabber-widget-alist) (widget-insert "\n") (push (cons 'EMAIL (widget-create '(repeat :tag "E-mail addresses" (cons :tag "Address" (set :tag "Type" (const :tag "Home" HOME) (const :tag "Work" WORK) (const :tag "Internet" INTERNET) (const :tag "X400" X400) (const :tag "Preferred" PREF)) (string :tag "Address"))) :value (cdr (assq 'EMAIL parsed)))) jabber-widget-alist) (widget-insert "\n") (widget-insert "Photo/avatar:\n") (let* ((photo (assq 'PHOTO parsed)) (avatar (when photo (jabber-avatar-from-base64-string (nth 2 photo) (nth 1 photo))))) (push (cons 'PHOTO (widget-create `(radio-button-choice (const :tag "None" nil) ,@(when photo (list `(const :tag ,(concat "Existing: " (jabber-propertize " " 'display (jabber-avatar-image avatar))) ,(cdr photo)))) (file :must-match t :tag "From file")) :value (cdr photo))) jabber-widget-alist)) (widget-insert "\n") (widget-create 'push-button :notify #'jabber-vcard-submit "Submit") (widget-setup) (widget-minor-mode 1) (switch-to-buffer (current-buffer)) (goto-char start-position)))) (defun jabber-vcard-submit (&rest ignore) (let ((to-publish (jabber-vcard-reassemble (mapcar (lambda (entry) (cons (car entry) (widget-value (cdr entry)))) jabber-widget-alist)))) (jabber-send-iq jabber-buffer-connection nil "set" to-publish #'jabber-report-success "Changing vCard" #'jabber-report-success "Changing vCard") (when (bound-and-true-p jabber-vcard-avatars-publish) (jabber-vcard-avatars-update-current jabber-buffer-connection (and jabber-vcard-photo (avatar-sha1-sum jabber-vcard-photo)))))) (provide 'jabber-vcard) ;; arch-tag: 65B95E9C-63BD-11D9-94A9-000A95C2FCD0 emacs-jabber-0.8.0/jabber-version.el0000644000175100017510000000551411133727374014224 00000000000000;; jabber-version.el - version reporting by JEP-0092 ;; Copyright (C) 2003, 2004, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-iq) (require 'jabber-util) (require 'jabber-ourversion) (add-to-list 'jabber-jid-info-menu (cons "Request software version" 'jabber-get-version)) (defun jabber-get-version (jc to) "Request software version" (interactive (list (jabber-read-account) (jabber-read-jid-completing "Request version of: " nil nil nil 'full))) (jabber-send-iq jc to "get" '(query ((xmlns . "jabber:iq:version"))) #'jabber-process-data #'jabber-process-version #'jabber-process-data "Version request failed")) ;; called by jabber-process-data (defun jabber-process-version (jc xml-data) "Handle results from jabber:iq:version requests." (let ((query (jabber-iq-query xml-data))) (dolist (x '((name . "Name:\t\t") (version . "Version:\t") (os . "OS:\t\t"))) (let ((data (car (jabber-xml-node-children (car (jabber-xml-get-children query (car x))))))) (when data (insert (cdr x) data "\n")))))) (add-to-list 'jabber-iq-get-xmlns-alist (cons "jabber:iq:version" 'jabber-return-version)) (add-to-list 'jabber-advertised-features "jabber:iq:version") (defun jabber-return-version (jc xml-data) "Return client version as defined in JEP-0092. Sender and ID are determined from the incoming packet passed in XML-DATA." ;; Things we might check: does this iq message really have type='get' and ;; exactly one child, namely query with xmlns='jabber:iq:version'? ;; Then again, jabber-process-iq should take care of that. (let ((to (jabber-xml-get-attribute xml-data 'from)) (id (jabber-xml-get-attribute xml-data 'id))) (jabber-send-iq jc to "result" `(query ((xmlns . "jabber:iq:version")) (name () "jabber.el") (version () ,jabber-version) ;; Booting... /vmemacs.el ;; Shamelessly stolen from someone's sig. (os () ,(emacs-version))) nil nil nil nil id))) (provide 'jabber-version) ;;; arch-tag: 2051dbe7-01b5-401e-bd8a-fe24afb88e1e emacs-jabber-0.8.0/jabber-watch.el0000644000175100017510000000570411133727374013646 00000000000000;; jabber-watch.el - get notified when certain persons go online ;; Copyright (C) 2004 - Mathias Dahl ;; Copyright (C) 2004 - Magnus Henoch - mange@freemail.hu ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'jabber-util) (defcustom jabber-watch-alist nil "Alist of buddies for which an extra notification should be sent when they come online, with comment strings as values." ;; XXX: change symbol to jid-symbol or something, and update ;; documentation :type '(alist :key-type symbol :value-type string) :group 'jabber-watch) (defun jabber-presence-watch (who oldstatus newstatus statustext proposed-alert) "Checks if one of your extra-important buddies comes online and sends a message if that happens. The buddies are stored in `jabber-watch-alist' and are added and removed by calling `jabber-watch-add' and `jabber-watch-remove.'" ;; check that buddy was previously offline and now online (if (and (null oldstatus) (not (null newstatus))) (let ((entry (assq who jabber-watch-alist))) (when entry ;; Give an intrusive message. With a window system, ;; that's easy. (if window-system (message-box "%s%s" proposed-alert (if (cdr entry) (format ": %s" (cdr entry)) "")) ;; Without a window system, yes-or-no-p should be ;; sufficient. (while (not (yes-or-no-p (format "%s%s Got that? " proposed-alert (if (cdr entry) (format ": %s" (cdr entry)) "")))))))))) (defun jabber-watch-add (buddy &optional comment) (interactive (list (jabber-read-jid-completing "Add buddy to watch list: ") (read-string "Comment: "))) (unless (memq 'jabber-presence-watch jabber-presence-hooks) (error "jabber-presence-watch is not in jabber-presence-hooks")) (add-to-list 'jabber-watch-alist (cons (jabber-jid-symbol buddy) (and (not (zerop (length comment))) comment)))) (defun jabber-watch-remove (buddy) (interactive (list (jabber-read-jid-completing "Remove buddy from watch list: " (or (mapcar 'car jabber-watch-alist) (error "Watch list is empty")) t))) (setq jabber-watch-alist (delq (assq (jabber-jid-symbol buddy) jabber-watch-alist) jabber-watch-alist))) (provide 'jabber-watch) ;; arch-tag: c27299d8-019e-44b5-9529-d67b8682be23 emacs-jabber-0.8.0/jabber-widget.el0000644000175100017510000003215511133727374014023 00000000000000;; jabber-widget.el - display various kinds of forms ;; Copyright (C) 2003, 2004, 2007 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'widget) (require 'wid-edit) (require 'jabber-util) (require 'jabber-disco) (defvar jabber-widget-alist nil "Alist of widgets currently used") (defvar jabber-form-type nil "Type of form. One of: 'x-data, jabber:x:data 'register, as used in jabber:iq:register and jabber:iq:search") (defvar jabber-submit-to nil "JID of the entity to which form data is to be sent") (add-to-list 'jabber-advertised-features "jabber:x:data") (define-widget 'jid 'string "JID widget." :value-to-internal (lambda (widget value) (let ((displayname (jabber-jid-rostername value))) (if displayname (format "%s <%s>" displayname value) value))) :value-to-external (lambda (widget value) (if (string-match "<\\([^>]+\\)>[ \t]*$" value) (match-string 1 value) value)) :complete-function 'jid-complete) (defun jid-complete () "Perform completion on JID preceding point." (interactive) ;; mostly stolen from widget-color-complete (let* ((prefix (buffer-substring-no-properties (widget-field-start widget) (point))) (list (append (mapcar #'symbol-name *jabber-roster*) (delq nil (mapcar #'(lambda (item) (when (jabber-jid-rostername item) (format "%s <%s>" (jabber-jid-rostername item) (symbol-name item)))) *jabber-roster*)))) (completion (try-completion prefix list))) (cond ((eq completion t) (message "Exact match.")) ((null completion) (error "Can't find completion for \"%s\"" prefix)) ((not (string-equal prefix completion)) (insert-and-inherit (substring completion (length prefix)))) (t (message "Making completion list...") (with-output-to-temp-buffer "*Completions*" (display-completion-list (all-completions prefix list nil) prefix)) (message "Making completion list...done"))))) (defun jabber-init-widget-buffer (submit-to) "Setup buffer-local variables for widgets." (make-local-variable 'jabber-widget-alist) (make-local-variable 'jabber-submit-to) (setq jabber-widget-alist nil) (setq jabber-submit-to submit-to) (setq buffer-read-only nil) ;; XXX: This is because data from other queries would otherwise be ;; appended to this buffer, which would fail since widget buffers ;; are read-only... or something like that. Maybe there's a ;; better way. (rename-uniquely)) (defun jabber-render-register-form (query &optional default-username) "Display widgets from element in jabber:iq:{register,search} namespace. DEFAULT-USERNAME is the default value for the username field." (make-local-variable 'jabber-widget-alist) (setq jabber-widget-alist nil) (make-local-variable 'jabber-form-type) (setq jabber-form-type 'register) (if (jabber-xml-get-children query 'instructions) (widget-insert "Instructions: " (car (jabber-xml-node-children (car (jabber-xml-get-children query 'instructions)))) "\n")) (if (jabber-xml-get-children query 'registered) (widget-insert "You are already registered. You can change your details here.\n")) (widget-insert "\n") (let ((possible-fields ;; taken from JEP-0077 '((username . "Username") (nick . "Nickname") (password . "Password") (name . "Full name") (first . "First name") (last . "Last name") (email . "E-mail") (address . "Address") (city . "City") (state . "State") (zip . "Zip") (phone . "Telephone") (url . "Web page") (date . "Birth date")))) (dolist (field (jabber-xml-node-children query)) (let ((entry (assq (jabber-xml-node-name field) possible-fields))) (when entry (widget-insert (cdr entry) "\t") ;; Special case: when registering a new account, the default ;; username is the one specified in jabber-username. Things ;; will break if the user changes that name, though... (let ((default-value (or (when (eq (jabber-xml-node-name field) 'username) default-username) ""))) (setq jabber-widget-alist (cons (cons (car entry) (widget-create 'editable-field :secret (if (eq (car entry) 'password) ?* nil) (or (car (jabber-xml-node-children field)) default-value))) jabber-widget-alist))) (widget-insert "\n")))))) (defun jabber-parse-register-form () "Return children of a tag containing information entered in the widgets of the current buffer." (mapcar (lambda (widget-cons) (list (car widget-cons) nil (widget-value (cdr widget-cons)))) jabber-widget-alist)) (defun jabber-render-xdata-form (x &optional defaults) "Display widgets from element in jabber:x:data namespace. DEFAULTS is an alist associating variable names with default values. DEFAULTS takes precedence over values specified in the form." (make-local-variable 'jabber-widget-alist) (setq jabber-widget-alist nil) (make-local-variable 'jabber-form-type) (setq jabber-form-type 'xdata) (let ((title (car (jabber-xml-node-children (car (jabber-xml-get-children x 'title)))))) (if (stringp title) (widget-insert (jabber-propertize title 'face 'jabber-title-medium) "\n\n"))) (let ((instructions (car (jabber-xml-node-children (car (jabber-xml-get-children x 'instructions)))))) (if (stringp instructions) (widget-insert "Instructions: " instructions "\n\n"))) (dolist (field (jabber-xml-get-children x 'field)) (let* ((var (jabber-xml-get-attribute field 'var)) (label (jabber-xml-get-attribute field 'label)) (type (jabber-xml-get-attribute field 'type)) (required (jabber-xml-get-children field 'required)) (values (jabber-xml-get-children field 'value)) (options (jabber-xml-get-children field 'option)) (desc (car (jabber-xml-get-children field 'desc))) (default-value (assoc var defaults))) ;; "required" not implemented yet (cond ((string= type "fixed") (widget-insert (car (jabber-xml-node-children (car values))))) ((string= type "text-multi") (if (or label var) (widget-insert (or label var) ":\n")) (push (cons (cons var type) (widget-create 'text (or (cdr default-value) (mapconcat #'(lambda (val) (car (jabber-xml-node-children val))) values "\n") ""))) jabber-widget-alist)) ((string= type "list-single") (if (or label var) (widget-insert (or label var) ":\n")) (push (cons (cons var type) (apply 'widget-create 'radio-button-choice :value (or (cdr default-value) (car (xml-node-children (car values)))) (mapcar (lambda (option) `(item :tag ,(jabber-xml-get-attribute option 'label) :value ,(car (jabber-xml-node-children (car (jabber-xml-get-children option 'value)))))) options))) jabber-widget-alist)) ((string= type "boolean") (push (cons (cons var type) (widget-create 'checkbox :tag (or label var) :value (if default-value (cdr default-value) (not (null (member (car (xml-node-children (car values))) '("1" "true"))))))) jabber-widget-alist) (if (or label var) (widget-insert " " (or label var) "\n"))) (t ; in particular including text-single and text-private (if (or label var) (widget-insert (or label var) ": ")) (setq jabber-widget-alist (cons (cons (cons var type) (widget-create 'editable-field :secret (if (string= type "text-private") ?* nil) (or (cdr default-value) (car (jabber-xml-node-children (car values))) ""))) jabber-widget-alist)))) (when (and desc (car (jabber-xml-node-children desc))) (widget-insert "\n" (car (jabber-xml-node-children desc)))) (widget-insert "\n")))) (defun jabber-parse-xdata-form () "Return an tag containing information entered in the widgets of the current buffer." `(x ((xmlns . "jabber:x:data") (type . "submit")) ,@(mapcar (lambda (widget-cons) (let ((values (jabber-xdata-value-convert (widget-value (cdr widget-cons)) (cdar widget-cons)))) ;; empty fields are not included (when values `(field ((var . ,(caar widget-cons))) ,@(mapcar (lambda (value) (list 'value nil value)) values))))) jabber-widget-alist))) (defun jabber-xdata-value-convert (value type) "Convert VALUE from form used by widget library to form required by JEP-0004. Return a list of strings, each of which to be included as cdata in a tag." (cond ((string= type "boolean") (if value (list "1") (list "0"))) ((string= type "text-multi") (split-string value "[\n\r]")) (t ; in particular including text-single, text-private and list-single (if (zerop (length value)) nil (list value))))) (defun jabber-render-xdata-search-results (xdata) "Render search results in x:data form." (let ((title (car (jabber-xml-get-children xdata 'title)))) (when title (insert (jabber-propertize (car (jabber-xml-node-children title)) 'face 'jabber-title-medium) "\n"))) (if (jabber-xml-get-children xdata 'reported) (jabber-render-xdata-search-results-multi xdata) (jabber-render-xdata-search-results-single xdata))) (defun jabber-render-xdata-search-results-multi (xdata) "Render multi-record search results." (let (fields (jid-fields 0)) (let ((reported (car (jabber-xml-get-children xdata 'reported))) (column 0)) (dolist (field (jabber-xml-get-children reported 'field)) (let (width) ;; Clever algorithm for estimating width based on field type goes here. (setq width 20) (setq fields (append fields (list (cons (jabber-xml-get-attribute field 'var) (list 'label (jabber-xml-get-attribute field 'label) 'type (jabber-xml-get-attribute field 'type) 'column column))))) (setq column (+ column width)) (if (string= (jabber-xml-get-attribute field 'type) "jid-single") (setq jid-fields (1+ jid-fields)))))) (dolist (field-cons fields) (indent-to (plist-get (cdr field-cons) 'column) 1) (insert (jabber-propertize (plist-get (cdr field-cons) 'label) 'face 'bold))) (insert "\n\n") ;; Now, the items (dolist (item (jabber-xml-get-children xdata 'item)) (let ((start-of-line (point)) jid) ;; The following code assumes that the order of the s in each ;; is the same as in the tag. (dolist (field (jabber-xml-get-children item 'field)) (let ((field-plist (cdr (assoc (jabber-xml-get-attribute field 'var) fields))) (value (car (jabber-xml-node-children (car (jabber-xml-get-children field 'value)))))) (indent-to (plist-get field-plist 'column) 1) ;; Absent values are sometimes "", sometimes nil. insert ;; doesn't like nil. (when value ;; If there is only one JID field, let the whole row ;; have the jabber-jid property. If there are many JID ;; fields, the string belonging to each field has that ;; property. (if (string= (plist-get field-plist 'type) "jid-single") (if (not (eq jid-fields 1)) (insert (jabber-propertize value 'jabber-jid value)) (setq jid value) (insert value)) (insert value))))) (if jid (put-text-property start-of-line (point) 'jabber-jid jid)) (insert "\n"))))) (defun jabber-render-xdata-search-results-single (xdata) "Render single-record search results." (dolist (field (jabber-xml-get-children xdata 'field)) (let ((label (jabber-xml-get-attribute field 'label)) (type (jabber-xml-get-attribute field 'type)) (values (mapcar #'(lambda (val) (car (jabber-xml-node-children val))) (jabber-xml-get-children field 'value)))) ;; XXX: consider type (insert (jabber-propertize (concat label ": ") 'face 'bold)) (indent-to 30) (insert (apply #'concat values) "\n")))) (defun jabber-xdata-formtype (x) "Return the form type of the xdata form in X, by JEP-0068. Return nil if no form type is specified." (catch 'found-formtype (dolist (field (jabber-xml-get-children x 'field)) (when (and (string= (jabber-xml-get-attribute field 'var) "FORM_TYPE") (string= (jabber-xml-get-attribute field 'type) "hidden")) (throw 'found-formtype (car (jabber-xml-node-children (car (jabber-xml-get-children field 'value))))))))) (provide 'jabber-widget) ;;; arch-tag: da3312f3-1970-41d5-a974-14b8d76156b8 emacs-jabber-0.8.0/jabber-wmii.el0000644000175100017510000000423211133727374013500 00000000000000;; jabber-wmii.el - emacs-jabber interface to wmii ;; Copyright (C) 2007 - Detlev Zundel - dzu@gnu.org ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'jabber-alert)) (defvar jabber-wmii-color "#ffffff #335577 #447799" "Color specification as needed by the wmii window manager for the jabber alert messages.") (defvar jabber-wmii-reset-time "20 sec" "If non-nil time to reset wmii message. If nil the message has to be cleared by other means, i.e. from wmiirc.") (defvar jabber-wmii-timer nil "Timer to clear wmii message.") (defun jabber-wmii-clear () "Clear any previous message output through wmii window manager." (condition-case e (call-process "wmiir" nil nil nil "remove" "/rbar/jabber") (error nil))) (defun jabber-wmii-message (msg) "Show MSG in wmii." (when jabber-wmii-timer (cancel-timer jabber-wmii-timer)) (let ((tmp (make-temp-file temporary-file-directory))) (with-temp-file tmp (insert jabber-wmii-color " " msg)) ;; Possible errors include not finding the wmiir binary, and ;; too many pipes open because of message flood. (condition-case e (call-process "wmiir" tmp nil nil "create" "/rbar/jabber") (error nil)) (delete-file tmp)) (when jabber-wmii-reset-time (setq jabber-wmii-timer (run-at-time jabber-wmii-reset-time nil 'jabber-wmii-clear)))) (define-jabber-alert wmii "Show a message through the wmii window manager." 'jabber-wmii-message) (provide 'jabber-wmii) emacs-jabber-0.8.0/jabber-xmessage.el0000644000175100017510000000325511133727374014353 00000000000000;; jabber-xmessage.el - emacs-jabber interface to xmessage ;; Copyright (C) 2008 - Magnus Henoch ;; Copyright (C) 2005 - Mario Domenech Goulart ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (eval-when-compile (require 'jabber-alert)) (defcustom jabber-xmessage-timeout 15 "Timeout in seconds for xmessage alerts. Set this to nil to have no timeout." :type '(choice (integer :tag "Seconds") (const :tag "No timeout" nil)) :group 'jabber-alerts) (defun jabber-xmessage-display-message (message) "Displays MESSAGE using the xmessage program." (let* ((process-connection-type nil) (timeout-args (when jabber-xmessage-timeout (list "-timeout" (number-to-string jabber-xmessage-timeout)))) (args (append timeout-args (list message)))) (apply 'start-process "xmessage" nil "xmessage" args))) (define-jabber-alert xmessage "Display a message using the xmessage program." 'jabber-xmessage-display-message) (provide 'jabber-xmessage) ;; arch-tag: 10A74D00-5D2C-11D9-A294-000A95C2FCD0 emacs-jabber-0.8.0/jabber-xml.el0000644000175100017510000001716711133727374013346 00000000000000;; jabber-xml.el - XML functions ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA (require 'xml) (require 'jabber-util) (defun jabber-escape-xml (str) "escape strings for xml" (if (stringp str) (let ((newstr (concat str))) ;; Form feeds might appear in code you copy, etc. Nevertheless, ;; it's invalid XML. (setq newstr (jabber-replace-in-string newstr "\f" "\n")) ;; Other control characters are also illegal, except for ;; tab, CR, and LF. (setq newstr (jabber-replace-in-string newstr "[\000-\010\013\014\016-\037]" " ")) (setq newstr (jabber-replace-in-string newstr "&" "&")) (setq newstr (jabber-replace-in-string newstr "<" "<")) (setq newstr (jabber-replace-in-string newstr ">" ">")) (setq newstr (jabber-replace-in-string newstr "'" "'")) (setq newstr (jabber-replace-in-string newstr "\"" """)) newstr) str)) (defun jabber-unescape-xml (str) "unescape xml strings" ;; Eventually this can be done with `xml-substitute-special', but the ;; version in xml.el of GNU Emacs 21.3 is buggy. (if (stringp str) (let ((newstr str)) (setq newstr (jabber-replace-in-string newstr """ "\"")) (setq newstr (jabber-replace-in-string newstr "'" "'")) (setq newstr (jabber-replace-in-string newstr ">" ">")) (setq newstr (jabber-replace-in-string newstr "<" "<")) (setq newstr (jabber-replace-in-string newstr "&" "&")) newstr) str)) (defun jabber-sexp2xml (sexp) "converts an SEXP in the format (tagname ((attribute-name . attribute-value)...) children...) and converts it to well-formatted xml." (cond ((stringp sexp) (jabber-escape-xml sexp)) ((listp (car sexp)) (let ((xml "")) (dolist (tag sexp) (setq xml (concat xml (jabber-sexp2xml tag)))) xml)) ;; work around bug in old versions of xml.el, where ("") can appear ;; as children of a node ((and (consp sexp) (stringp (car sexp)) (zerop (length (car sexp)))) "") (t (let ((xml "")) (setq xml (concat "<" (symbol-name (car sexp)))) (dolist (attr (cadr sexp)) (if (consp attr) (setq xml (concat xml (format " %s='%s'" (symbol-name (car attr)) (jabber-escape-xml (cdr attr))))))) (if (cddr sexp) (progn (setq xml (concat xml ">")) (dolist (child (cddr sexp)) (setq xml (concat xml (jabber-sexp2xml child)))) (setq xml (concat xml ""))) (setq xml (concat xml "/>"))) xml)))) (defun jabber-xml-skip-tag-forward (&optional dont-recurse-into-stream) "Skip to end of tag or matching closing tag if present. Return t iff after a closing tag, otherwise throws an 'unfinished tag with value nil. If DONT-RECURSE-INTO-STREAM is true, stop after an opening tag. The version of `sgml-skip-tag-forward' in Emacs 21 isn't good enough for us." (skip-chars-forward "^<") (cond ((looking-at "" nil t) (goto-char (match-end 0)) (throw 'unfinished nil))) ((looking-at "<\\([^ \t\n/>]+\\)\\([ \t\n]+[^=]+='[^']*'\\|[ \t\n]+[^=]+=\"[^\"]*\"\\)*") (let ((node-name (match-string 1))) (goto-char (match-end 0)) (cond ((looking-at "/>") (goto-char (match-end 0)) t) ((looking-at ">") (forward-char 1) (unless (and dont-recurse-into-stream (equal node-name "stream:stream")) (loop do (skip-chars-forward "^<") until (looking-at (regexp-quote (concat ""))) do (jabber-xml-skip-tag-forward)) (goto-char (match-end 0))) t) (t (throw 'unfinished nil))))) (t (throw 'unfinished nil)))) (defsubst jabber-xml-node-name (node) "Return the tag associated with NODE. The tag is a lower-case symbol." (if (listp node) (car node))) (defsubst jabber-xml-node-attributes (node) "Return the list of attributes of NODE. The list can be nil." (if (listp node) (nth 1 node))) (defsubst jabber-xml-node-children (node) "Return the list of children of NODE. This is a list of nodes, and it can be nil." (let ((children (cddr node))) ;; Work around a bug in early versions of xml.el (if (equal children '((""))) nil children))) (defun jabber-xml-get-children (node child-name) "Return the children of NODE whose tag is CHILD-NAME. CHILD-NAME should be a lower case symbol." (let ((match ())) (dolist (child (jabber-xml-node-children node)) (if child (if (equal (jabber-xml-node-name child) child-name) (push child match)))) (nreverse match))) ;; `xml-get-attribute' returns "" if the attribute is not found, which ;; is not very useful. Therefore, we use `xml-get-attribute-or-nil' ;; if present, or emulate its behavior. (eval-and-compile (if (fboundp 'xml-get-attribute-or-nil) (defsubst jabber-xml-get-attribute (node attribute) "Get from NODE the value of ATTRIBUTE. Return nil if the attribute was not found." (when (consp node) (xml-get-attribute-or-nil node attribute))) (defsubst jabber-xml-get-attribute (node attribute) "Get from NODE the value of ATTRIBUTE. Return nil if the attribute was not found." (when (consp node) (let ((result (xml-get-attribute node attribute))) (and (> (length result) 0) result)))))) (defsubst jabber-xml-get-xmlns (node) "Get \"xmlns\" attribute of NODE, or nil if not present." (jabber-xml-get-attribute node 'xmlns)) (defun jabber-xml-path (xml-data path) "Find sub-node of XML-DATA according to PATH. PATH is a vaguely XPath-inspired list. Each element can be: a symbol go to first child node with this node name cons cell car is string containing namespace URI, cdr is string containing node name. Find first matching child node. any string character data of this node" (let ((node xml-data)) (while (and path node) (let ((step (car path))) (cond ((symbolp step) (setq node (car (jabber-xml-get-children node step)))) ((consp step) ;; This will be easier with namespace-aware use ;; of xml.el. It will also be more correct. ;; Now, it only matches explicit namespace declarations. (setq node (dolist (x (jabber-xml-get-children node (intern (cdr step)))) (when (string= (jabber-xml-get-attribute x 'xmlns) (car step)) (return x))))) ((stringp step) (setq node (car (jabber-xml-node-children node))) (unless (stringp node) (setq node nil))) (t (error "Unknown path step: %s" step)))) (setq path (cdr path))) node)) (defmacro jabber-xml-let-attributes (attributes xml-data &rest body) "Bind variables to the same-name attribute values in XML-DATA." `(let ,(mapcar #'(lambda (attr) (list attr `(jabber-xml-get-attribute ,xml-data ',attr))) attributes) ,@body)) (put 'jabber-xml-let-attributes 'lisp-indent-function 2) (provide 'jabber-xml) ;;; arch-tag: ca206e65-7026-4ee8-9af2-ff6a9c5af98a emacs-jabber-0.8.0/jabber.el0000644000175100017510000001655611250455045012542 00000000000000;; jabber.el - a minimal jabber client ;; Copyright (C) 2003, 2004, 2007, 2008 - Magnus Henoch - mange@freemail.hu ;; Copyright (C) 2002, 2003, 2004 - tom berger - object@intelectronica.net ;; SSL - Support, mostly inspired by Gnus ;; Copyright (C) 2005 - Georg Lehner - jorge@magma.com.ni ;; This file is a part of jabber.el. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, write to the Free Software ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ;;; load Unicode tables if this needed (when (and (featurep 'xemacs) (not (emacs-version>= 21 5 5))) (require 'un-define)) ;;; these customize fields should come first (defgroup jabber nil "Jabber instant messaging" :group 'applications) ;;;###autoload (defcustom jabber-account-list nil "List of Jabber accounts. Each element of the list is a cons cell describing a Jabber account, where the car is a JID and the CDR is an alist. JID is a full Jabber ID string (e.g. foo@bar.tld). You can also specify the resource (e.g. foo@bar.tld/emacs). The following keys can be present in the alist: :password is a string to authenticate ourself against the server. It can be empty. :network-server is a string identifying the address to connect to, if it's different from the server part of the JID. :port is the port to use (default depends on connection type). :connection-type is a symbol. Valid symbols are `starttls', `network' and `ssl'. Only JID is mandatory. The rest can be guessed at run-time. Examples: Two accounts without any special configuration: \((\"foo@example.com\") (\"bar@example.net\")) One disabled account with a non-standard port: \((\"romeo@montague.net\" (:port . 5242) (:disabled . t))) If you don't have SRV and STARTTLS capabilities in your Emacs, configure a Google Talk account like this: \((\"username@gmail.com\" (:network-server . \"talk.google.com\") (:connection-type . ssl)))" :type '(repeat (cons :tag "Account information" (string :tag "JID") (set :format "%v" (cons :format "%v" (const :format "" :disabled) (const :tag "Disabled" t)) (cons :format "%v" (const :format "" :password) (string :tag "Password")) (cons :format "%v" (const :format "" :network-server) (string :tag "Network server")) (cons :format "%v" (const :format "" :port) (integer :tag "Port" 5222)) (cons :format "%v" (const :format "" :connection-type) (choice :tag "Connection type" ;; XXX: detect whether we have STARTTLS? option ;; for enforcing encryption? (const :tag "STARTTLS" starttls) (const :tag "Unencrypted" network) (const :tag "Legacy SSL/TLS" ssl)))))) :group 'jabber) ;;;###autoload (defcustom jabber-default-show "" "default show state" :type '(choice (const :tag "Online" "") (const :tag "Chatty" "chat") (const :tag "Away" "away") (const :tag "Extended away" "xa") (const :tag "Do not disturb" "dnd")) :group 'jabber) ;;;###autoload (defcustom jabber-default-status "" "default status string" :type 'string :group 'jabber) ;;;###autoload (defcustom jabber-default-priority 10 "default priority" :type 'integer :group 'jabber) ;;; guess internal dependencies! (require 'jabber-util) (require 'jabber-menu) (require 'jabber-xml) (require 'jabber-conn) (require 'jabber-core) (require 'jabber-logon) (require 'jabber-roster) (require 'jabber-presence) (require 'jabber-alert) (require 'jabber-chat) (require 'jabber-disco) (require 'jabber-iq) (require 'jabber-widget) (require 'jabber-register) (require 'jabber-search) (require 'jabber-browse) (require 'jabber-muc) (require 'jabber-muc-nick-completion) (require 'jabber-version) (require 'jabber-ahc-presence) (require 'jabber-modeline) (require 'jabber-watch) (require 'jabber-activity) (require 'jabber-vcard) (require 'jabber-events) (require 'jabber-chatstates) (require 'jabber-vcard-avatars) (require 'jabber-autoaway) (require 'jabber-time) (require 'jabber-truncate) (require 'jabber-ft-client) (require 'jabber-ft-server) (require 'jabber-socks5) ;; External notifiers (require 'jabber-screen) (require 'jabber-ratpoison) (require 'jabber-sawfish) (require 'jabber-festival) (require 'jabber-xmessage) (require 'jabber-wmii) (require 'jabber-osd) (require 'jabber-awesome) (require 'jabber-autoloads) ;;;###autoload (defvar *jabber-current-status* nil "the users current presence status") ;;;###autoload (defvar *jabber-current-show* nil "the users current presence show") ;;;###autoload (defvar *jabber-current-priority* nil "the user's current priority") (defvar *jabber-status-history* nil "history of status messages") (defgroup jabber-faces nil "faces for displaying jabber instant messaging" :group 'jabber) (defface jabber-title-small '((t (:weight bold :width semi-expanded :height 1.0 :inherit variable-pitch))) "face for small titles" :group 'jabber-faces) (defface jabber-title-medium '((t (:weight bold :width expanded :height 2.0 :inherit variable-pitch))) "face for medium titles" :group 'jabber-faces) (defface jabber-title-large '((t (:weight bold :width ultra-expanded :height 3.0 :inherit variable-pitch))) "face for large titles" :group 'jabber-faces) (defgroup jabber-debug nil "debugging options" :group 'jabber) ;;;###autoload (defcustom jabber-debug-log-xml nil "log all XML i/o in *-jabber-xml-log-JID-*" :type 'boolean :group 'jabber-debug) ;;;###autoload (defcustom jabber-debug-keep-process-buffers nil "If nil, kill process buffers when the process dies. Contents of process buffers might be useful for debugging." :type 'boolean :group 'jabber-debug) ;;;###autoload (defconst jabber-presence-faces '(("" . jabber-roster-user-online) ("away" . jabber-roster-user-away) ("xa" . jabber-roster-user-xa) ("dnd" . jabber-roster-user-dnd) ("chat" . jabber-roster-user-chatty) ("error" . jabber-roster-user-error) (nil . jabber-roster-user-offline)) "Mapping from presence types to faces") (defconst jabber-presence-strings `(("" . ,(jabber-propertize "Online" 'face 'jabber-roster-user-online)) ("away" . ,(jabber-propertize "Away" 'face 'jabber-roster-user-away)) ("xa" . ,(jabber-propertize "Extended Away" 'face 'jabber-roster-user-xa)) ("dnd" . ,(jabber-propertize "Do not Disturb" 'face 'jabber-roster-user-dnd)) ("chat" . ,(jabber-propertize "Chatty" 'face 'jabber-roster-user-chatty)) ("error" . ,(jabber-propertize "Error" 'face 'jabber-roster-user-error)) (nil . ,(jabber-propertize "Offline" 'face 'jabber-roster-user-offline))) "Mapping from presence types to readable, colorized strings") ;;;###autoload (defun jabber-customize () "customize jabber options" (interactive) (customize-group 'jabber)) ;;;###autoload (defun jabber-info () "open jabber.el manual" (interactive) (info "jabber")) (provide 'jabber) ;;; arch-tag: 5145153e-4d19-4dc2-800c-b1282feb155d emacs-jabber-0.8.0/srv.el0000644000175100017510000000723111250455045012115 00000000000000;;; srv.el --- perform SRV DNS requests ;; Copyright (C) 2005, 2007 Magnus Henoch ;; Author: Magnus Henoch ;; Keywords: comm ;; Version: 0.1 ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; This code implements RFC 2782 (SRV records). It requires a version ;; of dns.el that supports SRV records; look in Gnus CVS if you don't ;; have one. ;;; Code: (condition-case nil (require 'dns) (error nil)) (eval-when-compile (require 'cl)) (defun srv-lookup (target) "Perform SRV lookup of TARGET and return list of connection candidiates. TARGET is a string of the form \"_Service._Proto.Name\". Returns a list with elements of the form (HOST . PORT), where HOST is a hostname and PORT is a numeric port. The caller is supposed to make connection attempts in the order given, starting from the beginning of the list. The list is empty if no SRV records were found." (unless (boundp 'dns-query-types) (error "No dns.el available")) (unless (assq 'SRV dns-query-types) (error "dns.el doesn't support SRV lookups")) ;; `dns-query' used to be `query-dns'. Try both names for now. (let* ((result (if (fboundp 'query-dns) (query-dns target 'SRV t) (dns-query target 'SRV t))) (answers (mapcar #'(lambda (a) (cadr (assq 'data a))) (cadr (assq 'answers result)))) answers-by-priority weighted-result) (if (or (null answers) ;; Special case for "service decidedly not available" (and (eq (length answers) 1) (string= (cadr (assq 'target (car answers))) "."))) nil ;; Sort answers into groups of same priority. (dolist (a answers) (let* ((priority (cadr (assq 'priority a))) (entry (assq priority answers-by-priority))) (if entry (push a (cdr entry)) (push (cons priority (list a)) answers-by-priority)))) ;; Sort by priority. (setq answers-by-priority (sort answers-by-priority #'(lambda (a b) (< (car a) (car b))))) ;; Randomize by weight within priority groups. See ;; algorithm in RFC 2782. (dolist (p answers-by-priority) (let ((weight-acc 0) weight-order) ;; Assign running sum of weight to each entry. (dolist (a (cdr p)) (incf weight-acc (cadr (assq 'weight a))) (push (cons weight-acc a) weight-order)) (setq weight-order (nreverse weight-order)) ;; While elements remain, pick a random number between 0 and ;; weight-acc inclusive, and select the first entry whose ;; running sum is greater than or equal to this number. (while weight-order (let* ((r (random (1+ weight-acc))) (next-entry (dolist (a weight-order) (if (>= (car a) r) (return a))))) (push (cdr next-entry) weighted-result) (setq weight-order (delq next-entry weight-order)))))) ;; Extract hostnames and ports (mapcar #'(lambda (a) (cons (cadr (assq 'target a)) (cadr (assq 'port a)))) (nreverse weighted-result))))) (provide 'srv) ;; arch-tag: b43358f2-d241-11da-836e-000a95c2fcd0 ;;; srv.el ends here emacs-jabber-0.8.0/jabber-autoloads.el0000644000175100017510000004454711252670515014537 00000000000000;;; jabber-autoloads.el --- automatically extracted autoloads ;; ;;; Code: ;;;### (autoloads (jabber-info jabber-customize jabber-debug-keep-process-buffers ;;;;;; jabber-debug-log-xml jabber-default-priority jabber-default-status ;;;;;; jabber-default-show jabber-account-list) "jabber" "jabber.el" ;;;;;; (19106 23077)) ;;; Generated autoloads from jabber.el (defvar jabber-account-list nil "\ List of Jabber accounts. Each element of the list is a cons cell describing a Jabber account, where the car is a JID and the CDR is an alist. JID is a full Jabber ID string (e.g. foo@bar.tld). You can also specify the resource (e.g. foo@bar.tld/emacs). The following keys can be present in the alist: :password is a string to authenticate ourself against the server. It can be empty. :network-server is a string identifying the address to connect to, if it's different from the server part of the JID. :port is the port to use (default depends on connection type). :connection-type is a symbol. Valid symbols are `starttls', `network' and `ssl'. Only JID is mandatory. The rest can be guessed at run-time. Examples: Two accounts without any special configuration: \((\"foo@example.com\") (\"bar@example.net\")) One disabled account with a non-standard port: \((\"romeo@montague.net\" (:port . 5242) (:disabled . t))) If you don't have SRV and STARTTLS capabilities in your Emacs, configure a Google Talk account like this: \((\"username@gmail.com\" (:network-server . \"talk.google.com\") (:connection-type . ssl)))") (custom-autoload 'jabber-account-list "jabber" t) (defvar jabber-default-show "" "\ default show state") (custom-autoload 'jabber-default-show "jabber" t) (defvar jabber-default-status "" "\ default status string") (custom-autoload 'jabber-default-status "jabber" t) (defvar jabber-default-priority 10 "\ default priority") (custom-autoload 'jabber-default-priority "jabber" t) (defvar *jabber-current-status* nil "\ the users current presence status") (defvar *jabber-current-show* nil "\ the users current presence show") (defvar *jabber-current-priority* nil "\ the user's current priority") (defvar jabber-debug-log-xml nil "\ log all XML i/o in *-jabber-xml-log-JID-*") (custom-autoload 'jabber-debug-log-xml "jabber" t) (defvar jabber-debug-keep-process-buffers nil "\ If nil, kill process buffers when the process dies. Contents of process buffers might be useful for debugging.") (custom-autoload 'jabber-debug-keep-process-buffers "jabber" t) (defconst jabber-presence-faces '(("" . jabber-roster-user-online) ("away" . jabber-roster-user-away) ("xa" . jabber-roster-user-xa) ("dnd" . jabber-roster-user-dnd) ("chat" . jabber-roster-user-chatty) ("error" . jabber-roster-user-error) (nil . jabber-roster-user-offline)) "\ Mapping from presence types to faces") (autoload 'jabber-customize "jabber" "\ customize jabber options \(fn)" t nil) (autoload 'jabber-info "jabber" "\ open jabber.el manual \(fn)" t nil) ;;;*** ;;;### (autoloads (jabber-activity-mode) "jabber-activity" "jabber-activity.el" ;;;;;; (19106 23077)) ;;; Generated autoloads from jabber-activity.el (defvar jabber-activity-mode t "\ Non-nil if Jabber-Activity mode is enabled. See the command `jabber-activity-mode' for a description of this minor mode. Setting this variable directly does not take effect; either customize it (see the info node `Easy Customization') or call the function `jabber-activity-mode'.") (custom-autoload 'jabber-activity-mode "jabber-activity" nil) (autoload 'jabber-activity-mode "jabber-activity" "\ Toggle display of activity in hidden jabber buffers in the mode line. With a numeric arg, enable this display if arg is positive. \(fn &optional ARG)" t nil) ;;;*** ;;;### (autoloads (jabber-autoaway-start) "jabber-autoaway" "jabber-autoaway.el" ;;;;;; (18799 44796)) ;;; Generated autoloads from jabber-autoaway.el (autoload 'jabber-autoaway-start "jabber-autoaway" "\ Start autoaway timer. The IGNORED argument is there so you can put this function in `jabber-post-connect-hooks'. \(fn &optional IGNORED)" t nil) ;;;*** ;;;### (autoloads (jabber-edit-bookmarks jabber-get-bookmarks-from-cache ;;;;;; jabber-get-bookmarks jabber-parse-conference-bookmark jabber-get-conference-data) ;;;;;; "jabber-bookmarks" "jabber-bookmarks.el" (18799 44796)) ;;; Generated autoloads from jabber-bookmarks.el (autoload 'jabber-get-conference-data "jabber-bookmarks" "\ Get bookmark data for CONFERENCE-JID. KEY may be nil or one of :name, :autojoin, :nick and :password. If KEY is nil, a plist containing the above keys is returned. CONT is called when the result is available, with JC and the result as arguments. If CONT is nil, return the requested data immediately, and return nil if it is not in the cache. \(fn JC CONFERENCE-JID CONT &optional KEY)" nil nil) (autoload 'jabber-parse-conference-bookmark "jabber-bookmarks" "\ Convert a tag into a plist. The plist may contain the keys :jid, :name, :autojoin, :nick and :password. \(fn NODE)" nil nil) (autoload 'jabber-get-bookmarks "jabber-bookmarks" "\ Retrieve bookmarks (if needed) and call CONT. Arguments to CONT are JC and the bookmark list. CONT will be called as the result of a filter function or a timer. If REFRESH is non-nil, always fetch bookmarks. \(fn JC CONT &optional REFRESH)" nil nil) (autoload 'jabber-get-bookmarks-from-cache "jabber-bookmarks" "\ Return cached bookmarks for JC. If bookmarks have not yet been fetched by `jabber-get-bookmarks', return nil. \(fn JC)" nil nil) (autoload 'jabber-edit-bookmarks "jabber-bookmarks" "\ Create a buffer for editing bookmarks interactively. \(fn JC)" t nil) ;;;*** ;;;### (autoloads (jabber-chat-get-buffer) "jabber-chat" "jabber-chat.el" ;;;;;; (19106 23077)) ;;; Generated autoloads from jabber-chat.el (defvar jabber-chatting-with nil "\ JID of the person you are chatting with") (autoload 'jabber-chat-get-buffer "jabber-chat" "\ Return the chat buffer for chatting with CHAT-WITH (bare or full JID). Either a string or a buffer is returned, so use `get-buffer' or `get-buffer-create'. \(fn CHAT-WITH)" nil nil) ;;;*** ;;;### (autoloads nil "jabber-chatbuffer" "jabber-chatbuffer.el" ;;;;;; (18799 44796)) ;;; Generated autoloads from jabber-chatbuffer.el (defvar jabber-buffer-connection nil "\ The connection used by this buffer.") (make-variable-buffer-local 'jabber-buffer-connection) ;;;*** ;;;### (autoloads (jabber-compose) "jabber-compose" "jabber-compose.el" ;;;;;; (18799 44796)) ;;; Generated autoloads from jabber-compose.el (autoload 'jabber-compose "jabber-compose" "\ Create a buffer for composing a Jabber message. \(fn JC &optional RECIPIENT)" t nil) ;;;*** ;;;### (autoloads nil "jabber-core" "jabber-core.el" (19106 23077)) ;;; Generated autoloads from jabber-core.el (autoload 'jabber-connect-all "jabber" "Connect to all configured Jabber accounts.\nSee `jabber-account-list'.\nIf no accounts are configured (or ARG supplied), call `jabber-connect' interactively." t) (autoload 'jabber-connect "jabber" "Connect to the Jabber server and start a Jabber XML stream.\nWith prefix argument, register a new account.\nWith double prefix argument, specify more connection details." t) ;;;*** ;;;### (autoloads (jabber-import-roster jabber-export-roster) "jabber-export" ;;;;;; "jabber-export.el" (18799 44796)) ;;; Generated autoloads from jabber-export.el (autoload 'jabber-export-roster "jabber-export" "\ Export roster for connection JC. \(fn JC)" t nil) (autoload 'jabber-import-roster "jabber-export" "\ Create buffer for roster import for connection JC from FILE. \(fn JC FILE)" t nil) ;;;*** ;;;### (autoloads (jabber-gmail-query jabber-gmail-subscribe) "jabber-gmail" ;;;;;; "jabber-gmail.el" (18799 44796)) ;;; Generated autoloads from jabber-gmail.el (autoload 'jabber-gmail-subscribe "jabber-gmail" "\ Subscribe to gmail notifications. See http://code.google.com/apis/talk/jep_extensions/usersettings.html#4 \(fn JC)" t nil) (autoload 'jabber-gmail-query "jabber-gmail" "\ Request mail information from the Google Talk server (a.k.a. one shot query). See http://code.google.com/apis/talk/jep_extensions/gmail.html#requestmail \(fn JC)" t nil) ;;;*** ;;;### (autoloads (jabber-whitespace-ping-start jabber-whitespace-ping-interval ;;;;;; jabber-keepalive-start jabber-keepalive-timeout jabber-keepalive-interval ;;;;;; jabber-keepalive) "jabber-keepalive" "jabber-keepalive.el" ;;;;;; (18799 44796)) ;;; Generated autoloads from jabber-keepalive.el (let ((loads (get 'jabber-keepalive 'custom-loads))) (if (member '"jabber-keepalive" loads) nil (put 'jabber-keepalive 'custom-loads (cons '"jabber-keepalive" loads)))) (defvar jabber-keepalive-interval 600 "\ Interval in seconds between connection checks.") (custom-autoload 'jabber-keepalive-interval "jabber-keepalive" t) (defvar jabber-keepalive-timeout 20 "\ Seconds to wait for response from server.") (custom-autoload 'jabber-keepalive-timeout "jabber-keepalive" t) (autoload 'jabber-keepalive-start "jabber-keepalive" "\ Activate keepalive. That is, regularly send a ping request to the server, and disconnect if it doesn't answer. See `jabber-keepalive-interval' and `jabber-keepalive-timeout'. The JC argument makes it possible to add this function to `jabber-post-connect-hooks'; it is ignored. Keepalive is activated for all accounts regardless of the argument. \(fn &optional JC)" t nil) (defvar jabber-whitespace-ping-interval 30 "\ Send a space character to the server with this interval, in seconds. This is a traditional remedy for a number of problems: to keep NAT boxes from considering the connection dead, to have the OS discover earlier that the connection is lost, and to placate servers which rely on the client doing this, e.g. Openfire. If you want to verify that the server is able to answer, see `jabber-keepalive-start' for another mechanism.") (custom-autoload 'jabber-whitespace-ping-interval "jabber-keepalive" t) (autoload 'jabber-whitespace-ping-start "jabber-keepalive" "\ Start sending whitespace pings at regular intervals. See `jabber-whitespace-ping-interval'. The JC argument is ignored; whitespace pings are enabled for all accounts. \(fn &optional JC)" t nil) ;;;*** ;;;### (autoloads nil "jabber-keymap" "jabber-keymap.el" (18799 44796)) ;;; Generated autoloads from jabber-keymap.el (defvar jabber-global-keymap (let ((map (make-sparse-keymap))) (define-key map "" 'jabber-connect-all) (define-key map "" 'jabber-disconnect) (define-key map "" 'jabber-switch-to-roster-buffer) (define-key map "\n" 'jabber-chat-with) (define-key map "\f" 'jabber-activity-switch-to) (define-key map "" 'jabber-send-away-presence) (define-key map "" 'jabber-send-default-presence) (define-key map "" 'jabber-send-xa-presence) (define-key map "" 'jabber-send-presence) map) "\ Global Jabber keymap (usually under C-x C-j)") (define-key ctl-x-map "\n" jabber-global-keymap) ;;;*** ;;;### (autoloads (jabber-display-menu) "jabber-menu" "jabber-menu.el" ;;;;;; (19106 23077)) ;;; Generated autoloads from jabber-menu.el (defvar jabber-menu (let ((map (make-sparse-keymap "jabber-menu"))) (define-key map [jabber-menu-connect] '("Connect" . jabber-connect-all)) (define-key map [jabber-menu-disconnect] '("Disconnect" . jabber-disconnect)) (define-key map [jabber-menu-roster] '("Switch to roster" . jabber-switch-to-roster-buffer)) (define-key map [jabber-menu-customize] '("Customize" . jabber-customize)) (define-key map [jabber-menu-info] '("Help" . jabber-info)) (define-key map [jabber-menu-status] (cons "Set Status" (make-sparse-keymap "set-status"))) (define-key map [jabber-menu-status jabber-menu-status-chat] '("Chatty" lambda nil (interactive) (jabber-send-presence "chat" (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*) *jabber-current-priority*))) (define-key map [jabber-menu-status jabber-menu-status-dnd] '("Do not Disturb" lambda nil (interactive) (jabber-send-presence "dnd" (jabber-read-with-input-method "status message: " *jabber-current-status* '*jabber-status-history*) *jabber-current-priority*))) (define-key map [jabber-menu-status jabber-menu-status-xa] '("Extended Away" . jabber-send-xa-presence)) (define-key map [jabber-menu-status jabber-menu-status-away] '("Away" . jabber-send-away-presence)) (define-key map [jabber-menu-status jabber-menu-status-online] '("Online" . jabber-send-default-presence)) map)) (defvar jabber-display-menu 'maybe "\ Decide whether the \"Jabber\" menu is displayed in the menu bar. If t, always display. If nil, never display. If maybe, display if any of `jabber-account-list' or `jabber-connections' is non-nil.") (custom-autoload 'jabber-display-menu "jabber-menu" t) (define-key-after (lookup-key global-map [menu-bar]) [jabber-menu] (list 'menu-item "Jabber" jabber-menu :visible '(or (eq jabber-display-menu t) (and (eq jabber-display-menu 'maybe) (or jabber-account-list (bound-and-true-p jabber-connections)))))) ;;;*** ;;;### (autoloads (jabber-muc-private-message-p jabber-muc-sender-p ;;;;;; jabber-muc-message-p jabber-muc-private-get-buffer jabber-muc-get-buffer ;;;;;; jabber-muc-autojoin jabber-muc-default-nicknames) "jabber-muc" ;;;;;; "jabber-muc.el" (19106 23077)) ;;; Generated autoloads from jabber-muc.el (defvar *jabber-active-groupchats* nil "\ alist of groupchats and nicknames Keys are strings, the bare JID of the room. Values are strings.") (defvar jabber-muc-default-nicknames nil "\ Default nickname for specific MUC rooms.") (custom-autoload 'jabber-muc-default-nicknames "jabber-muc" t) (defvar jabber-muc-autojoin nil "\ List of MUC rooms to automatically join on connection. This list is saved in your Emacs customizations. You can also store such a list on the Jabber server, where it is available to every client; see `jabber-edit-bookmarks'.") (custom-autoload 'jabber-muc-autojoin "jabber-muc" t) (defvar jabber-muc-printers 'nil "\ List of functions that may be able to print part of a MUC message. This gets prepended to `jabber-chat-printers', which see.") (autoload 'jabber-muc-get-buffer "jabber-muc" "\ Return the chat buffer for chatroom GROUP. Either a string or a buffer is returned, so use `get-buffer' or `get-buffer-create'. \(fn GROUP)" nil nil) (autoload 'jabber-muc-private-get-buffer "jabber-muc" "\ Return the chat buffer for private chat with NICKNAME in GROUP. Either a string or a buffer is returned, so use `get-buffer' or `get-buffer-create'. \(fn GROUP NICKNAME)" nil nil) (autoload 'jabber-muc-message-p "jabber-muc" "\ Return non-nil if MESSAGE is a groupchat message. That does not include private messages in a groupchat, but does include groupchat invites. \(fn MESSAGE)" nil nil) (autoload 'jabber-muc-sender-p "jabber-muc" "\ Return non-nil if JID is a full JID of an MUC participant. \(fn JID)" nil nil) (autoload 'jabber-muc-private-message-p "jabber-muc" "\ Return non-nil if MESSAGE is a private message in a groupchat. \(fn MESSAGE)" nil nil) ;;;*** ;;;### (autoloads (jabber-muc-looks-like-personal-p) "jabber-muc-nick-completion" ;;;;;; "jabber-muc-nick-completion.el" (18799 44796)) ;;; Generated autoloads from jabber-muc-nick-completion.el (autoload 'jabber-muc-looks-like-personal-p "jabber-muc-nick-completion" "\ Return non-nil if jabber MESSAGE is addresed to me. Optional argument GROUP to look. \(fn MESSAGE &optional GROUP)" nil nil) ;;;*** ;;;### (autoloads (jabber-send-default-presence jabber-send-presence) ;;;;;; "jabber-presence" "jabber-presence.el" (19106 23077)) ;;; Generated autoloads from jabber-presence.el (autoload 'jabber-send-presence "jabber-presence" "\ Set presence for all accounts. \(fn SHOW STATUS PRIORITY)" t nil) (autoload 'jabber-send-default-presence "jabber-presence" "\ Send default presence. Default presence is specified by `jabber-default-show', `jabber-default-status', and `jabber-default-priority'. \(fn &optional IGNORE)" t nil) ;;;*** ;;;### (autoloads (jabber-private-set jabber-private-get) "jabber-private" ;;;;;; "jabber-private.el" (18799 44796)) ;;; Generated autoloads from jabber-private.el (autoload 'jabber-private-get "jabber-private" "\ Retrieve an item from private XML storage. The item to retrieve is identified by NODE-NAME (a symbol) and NAMESPACE (a string). On success, SUCCESS-CALLBACK is called with JC and the retrieved XML fragment. On error, ERROR-CALLBACK is called with JC and the entire IQ result. \(fn JC NODE-NAME NAMESPACE SUCCESS-CALLBACK ERROR-CALLBACK)" nil nil) (autoload 'jabber-private-set "jabber-private" "\ Store FRAGMENT in private XML storage. SUCCESS-CALLBACK, SUCCESS-CLOSURE-DATA, ERROR-CALLBACK and ERROR-CLOSURE-DATA are used as in `jabber-send-iq'. \(fn JC FRAGMENT &optional SUCCESS-CALLBACK SUCCESS-CLOSURE-DATA ERROR-CALLBACK ERROR-CLOSURE-DATA)" nil nil) ;;;*** ;;;### (autoloads (jabber-roster-update jabber-switch-to-roster-buffer) ;;;;;; "jabber-roster" "jabber-roster.el" (19106 23077)) ;;; Generated autoloads from jabber-roster.el (autoload 'jabber-switch-to-roster-buffer "jabber-roster" "\ Switch to roster buffer. Optional JC argument is ignored; it's there so this function can be used in `jabber-post-connection-hooks'. \(fn &optional JC)" t nil) (autoload 'jabber-roster-update "jabber-roster" "\ Update roster, in memory and on display. Add NEW-ITEMS, update CHANGED-ITEMS and remove DELETED-ITEMS, all three being lists of JID symbols. \(fn JC NEW-ITEMS CHANGED-ITEMS DELETED-ITEMS)" nil nil) ;;;*** ;;;### (autoloads nil nil ("fsm.el" "jabber-ahc-presence.el" "jabber-ahc.el" ;;;;;; "jabber-alert.el" "jabber-avatar.el" "jabber-awesome.el" ;;;;;; "jabber-browse.el" "jabber-chatstates.el" "jabber-conn.el" ;;;;;; "jabber-disco.el" "jabber-events.el" "jabber-feature-neg.el" ;;;;;; "jabber-festival.el" "jabber-ft-client.el" "jabber-ft-common.el" ;;;;;; "jabber-ft-server.el" "jabber-history.el" "jabber-iq.el" ;;;;;; "jabber-libnotify.el" "jabber-logon.el" "jabber-modeline.el" ;;;;;; "jabber-newdisco.el" "jabber-osd.el" "jabber-ourversion.el" ;;;;;; "jabber-ratpoison.el" "jabber-register.el" "jabber-sasl.el" ;;;;;; "jabber-sawfish.el" "jabber-screen.el" "jabber-search.el" ;;;;;; "jabber-si-client.el" "jabber-si-common.el" "jabber-si-server.el" ;;;;;; "jabber-socks5.el" "jabber-time.el" "jabber-truncate.el" ;;;;;; "jabber-util.el" "jabber-vcard-avatars.el" "jabber-vcard.el" ;;;;;; "jabber-version.el" "jabber-watch.el" "jabber-widget.el" ;;;;;; "jabber-wmii.el" "jabber-xmessage.el" "jabber-xml.el" "srv.el") ;;;;;; (19115 28984 832298)) ;;;*** (provide 'jabber-autoloads) ;; Local Variables: ;; version-control: never ;; no-byte-compile: t ;; no-update-autoloads: t ;; End: ;;; jabber-autoloads.el ends here emacs-jabber-0.8.0/jabber-ourversion.el0000644000175100017510000000040211252704731014733 00000000000000;; jabber-ourversion.el. Generated from jabber-ourversion.el.in by configure. ;; This value gets updated automatically when configure.ac is changed. (defconst jabber-version "0.8.0" "version returned to those who query us") (provide 'jabber-ourversion) emacs-jabber-0.8.0/emacs-jabber-uri-handler0000755000175100017510000000024311133727374015435 00000000000000#!/bin/sh # Pass XMPP URIs to jabber.el. See `(jabber)XMPP URIs'. emacsclient -e "(jabber-handle-uri \"$1\")" # arch-tag: 3b655d90-0247-11db-86ba-000a95c2fcd0 emacs-jabber-0.8.0/Makefile.am0000644000175100017510000000621611252704522013016 00000000000000ACLOCAL_AMFLAGS = -I m4 # The following line needs to be here since automake 1.4 doesn't look # for options in configure.ac. AUTOMAKE_OPTIONS = 1.9 my_lisp_sources=fsm.el jabber-activity.el jabber-ahc-presence.el \ jabber-ahc.el jabber-alert.el jabber-autoaway.el jabber-avatar.el \ jabber-awesome.el \ jabber-bookmarks.el jabber-browse.el jabber-chat.el \ jabber-chatbuffer.el jabber-chatstates.el jabber-compose.el \ jabber-conn.el jabber-core.el jabber-disco.el jabber-events.el \ jabber-export.el jabber-feature-neg.el jabber-festival.el \ jabber-ft-client.el jabber-ft-common.el jabber-ft-server.el \ jabber-gmail.el jabber-history.el jabber-iq.el jabber-keepalive.el \ jabber-keymap.el jabber-logon.el jabber-menu.el jabber-modeline.el \ jabber-muc-nick-completion.el jabber-muc.el jabber-newdisco.el \ jabber-osd.el jabber-presence.el jabber-private.el jabber-ratpoison.el \ jabber-register.el jabber-roster.el jabber-sasl.el jabber-sawfish.el \ jabber-screen.el jabber-search.el jabber-si-client.el \ jabber-si-common.el jabber-si-server.el jabber-socks5.el \ jabber-time.el jabber-truncate.el jabber-util.el \ jabber-vcard-avatars.el jabber-vcard.el jabber-version.el \ jabber-watch.el jabber-widget.el jabber-wmii.el jabber-xmessage.el \ jabber-xml.el jabber.el srv.el compat_lisp_sources = if USE_OUR_SHA1 compat_lisp_sources += compat/sha1.el endif if USE_OUR_HEX_UTIL compat_lisp_sources += compat/hex-util.el endif # automake gets confused and doesn't clean up these two compiled files. CLEANFILES=sha1.elc hex-util.elc dist_lisp_LISP=$(my_lisp_sources) $(compat_lisp_sources) jabber-autoloads.el jabber-ourversion.el MAINTAINERCLEANFILES=jabber-autoloads.el EXTRA_DIST = jabber-pkg.el.in # The autoload file will cause Lisp sources to be rebuilt _twice_: the # timestamp of the Lisp compilation is set _before_ the autoloads are # regenerated, which means that jabber-autoload.el is once again # considered new, which means that everything will be built again. # Suggestions welcome. # # Emacs 21 requires that the file already exist and have non-zero # size, so we touch it with ancient timestamp. jabber-autoloads.el: $(my_lisp_sources) test -s $@ || cp -f $(srcdir)/jabber-autoloads.stub $@; touch -t 197001030000 $@ $(EMACS) --batch --eval "(setq generated-autoload-file \"$(abs_builddir)/$@\")" -f batch-update-autoloads $(srcdir) info_TEXINFOS=jabber.texi dist_libexec_SCRIPTS = emacs-jabber-uri-handler SUBDIRS = . tests if USE_GCONFTOOL if GCONF_SCHEMAS_INSTALL SUBDIRS += gconf endif endif # Package everything in a form suitable for ELPA. That is, use # "jabber" instead of "emacs-jabber" as base name. CLEANFILES += jabber-pkg.el elpa: dist rm -rf emacs-jabber-$(PACKAGE_VERSION) jabber-$(PACKAGE_VERSION) $(AMTAR) xzf emacs-jabber-$(PACKAGE_VERSION).tar.gz mv emacs-jabber-$(PACKAGE_VERSION) jabber-$(PACKAGE_VERSION) cd jabber-$(PACKAGE_VERSION) ; install-info jabber.info dir sed "s/@""PACKAGE_VERSION@""/$(PACKAGE_VERSION)/" < $(srcdir)/jabber-pkg.el.in > jabber-$(PACKAGE_VERSION)/jabber-pkg.el $(AMTAR) chf jabber-$(PACKAGE_VERSION).tar jabber-$(PACKAGE_VERSION) rm -rf jabber-$(PACKAGE_VERSION) @echo "Created jabber-$(PACKAGE_VERSION).tar" emacs-jabber-0.8.0/Makefile.in0000644000175100017510000010743711252704652013042 00000000000000# Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : @USE_OUR_SHA1_TRUE@am__append_1 = compat/sha1.el @USE_OUR_HEX_UTIL_TRUE@am__append_2 = compat/hex-util.el @GCONF_SCHEMAS_INSTALL_TRUE@@USE_GCONFTOOL_TRUE@am__append_3 = gconf subdir = . DIST_COMMON = README $(am__configure_deps) $(am__dist_lisp_LISP_DIST) \ $(dist_libexec_SCRIPTS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/jabber-ourversion.el.in \ $(top_srcdir)/configure AUTHORS NEWS elisp-comp install-sh \ missing texinfo.tex ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/emacs-lib.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = jabber-ourversion.el am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(infodir)" \ "$(DESTDIR)$(lispdir)" dist_libexecSCRIPT_INSTALL = $(INSTALL_SCRIPT) SCRIPTS = $(dist_libexec_SCRIPTS) SOURCES = DIST_SOURCES = INFO_DEPS = $(srcdir)/jabber.info am__TEXINFO_TEX_DIR = $(srcdir) DVIS = jabber.dvi PDFS = jabber.pdf PSS = jabber.ps HTMLS = jabber.html TEXINFOS = jabber.texi TEXI2DVI = texi2dvi TEXI2PDF = $(TEXI2DVI) --pdf --batch MAKEINFOHTML = $(MAKEINFO) --html AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) DVIPS = dvips RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__dist_lisp_LISP_DIST = fsm.el jabber-activity.el \ jabber-ahc-presence.el jabber-ahc.el jabber-alert.el \ jabber-autoaway.el jabber-avatar.el jabber-awesome.el \ jabber-bookmarks.el jabber-browse.el jabber-chat.el \ jabber-chatbuffer.el jabber-chatstates.el jabber-compose.el \ jabber-conn.el jabber-core.el jabber-disco.el jabber-events.el \ jabber-export.el jabber-feature-neg.el jabber-festival.el \ jabber-ft-client.el jabber-ft-common.el jabber-ft-server.el \ jabber-gmail.el jabber-history.el jabber-iq.el \ jabber-keepalive.el jabber-keymap.el jabber-logon.el \ jabber-menu.el jabber-modeline.el \ jabber-muc-nick-completion.el jabber-muc.el jabber-newdisco.el \ jabber-osd.el jabber-presence.el jabber-private.el \ jabber-ratpoison.el jabber-register.el jabber-roster.el \ jabber-sasl.el jabber-sawfish.el jabber-screen.el \ jabber-search.el jabber-si-client.el jabber-si-common.el \ jabber-si-server.el jabber-socks5.el jabber-time.el \ jabber-truncate.el jabber-util.el jabber-vcard-avatars.el \ jabber-vcard.el jabber-version.el jabber-watch.el \ jabber-widget.el jabber-wmii.el jabber-xmessage.el \ jabber-xml.el jabber.el srv.el compat/sha1.el \ compat/hex-util.el jabber-autoloads.el jabber-ourversion.el dist_lispLISP_INSTALL = $(INSTALL_DATA) LISP = $(dist_lisp_LISP) am__ELFILES = compat/hex-util.el compat/sha1.el fsm.el \ jabber-activity.el jabber-ahc-presence.el jabber-ahc.el \ jabber-alert.el jabber-autoaway.el jabber-autoloads.el \ jabber-avatar.el jabber-awesome.el jabber-bookmarks.el \ jabber-browse.el jabber-chat.el jabber-chatbuffer.el \ jabber-chatstates.el jabber-compose.el jabber-conn.el \ jabber-core.el jabber-disco.el jabber-events.el \ jabber-export.el jabber-feature-neg.el jabber-festival.el \ jabber-ft-client.el jabber-ft-common.el jabber-ft-server.el \ jabber-gmail.el jabber-history.el jabber-iq.el \ jabber-keepalive.el jabber-keymap.el jabber-logon.el \ jabber-menu.el jabber-modeline.el \ jabber-muc-nick-completion.el jabber-muc.el jabber-newdisco.el \ jabber-osd.el jabber-ourversion.el jabber-presence.el \ jabber-private.el jabber-ratpoison.el jabber-register.el \ jabber-roster.el jabber-sasl.el jabber-sawfish.el \ jabber-screen.el jabber-search.el jabber-si-client.el \ jabber-si-common.el jabber-si-server.el jabber-socks5.el \ jabber-time.el jabber-truncate.el jabber-util.el \ jabber-vcard-avatars.el jabber-vcard.el jabber-version.el \ jabber-watch.el jabber-widget.el jabber-wmii.el \ jabber-xmessage.el jabber-xml.el jabber.el srv.el am__ELCFILES = $(am__ELFILES:.el=.elc) ELCFILES = $(LISP:.el=.elc) elisp_comp = $(top_srcdir)/elisp-comp RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive ETAGS = etags CTAGS = ctags DIST_SUBDIRS = . tests gconf DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 \ $(distdir).tar.lzma $(distdir).zip GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EMACS = @EMACS@ EMACSLOADPATH = @EMACSLOADPATH@ GCONFTOOL = @GCONFTOOL@ GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@ GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ lispdir = @lispdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 # The following line needs to be here since automake 1.4 doesn't look # for options in configure.ac. AUTOMAKE_OPTIONS = 1.9 my_lisp_sources = fsm.el jabber-activity.el jabber-ahc-presence.el \ jabber-ahc.el jabber-alert.el jabber-autoaway.el jabber-avatar.el \ jabber-awesome.el \ jabber-bookmarks.el jabber-browse.el jabber-chat.el \ jabber-chatbuffer.el jabber-chatstates.el jabber-compose.el \ jabber-conn.el jabber-core.el jabber-disco.el jabber-events.el \ jabber-export.el jabber-feature-neg.el jabber-festival.el \ jabber-ft-client.el jabber-ft-common.el jabber-ft-server.el \ jabber-gmail.el jabber-history.el jabber-iq.el jabber-keepalive.el \ jabber-keymap.el jabber-logon.el jabber-menu.el jabber-modeline.el \ jabber-muc-nick-completion.el jabber-muc.el jabber-newdisco.el \ jabber-osd.el jabber-presence.el jabber-private.el jabber-ratpoison.el \ jabber-register.el jabber-roster.el jabber-sasl.el jabber-sawfish.el \ jabber-screen.el jabber-search.el jabber-si-client.el \ jabber-si-common.el jabber-si-server.el jabber-socks5.el \ jabber-time.el jabber-truncate.el jabber-util.el \ jabber-vcard-avatars.el jabber-vcard.el jabber-version.el \ jabber-watch.el jabber-widget.el jabber-wmii.el jabber-xmessage.el \ jabber-xml.el jabber.el srv.el compat_lisp_sources = $(am__append_1) $(am__append_2) # automake gets confused and doesn't clean up these two compiled files. # Package everything in a form suitable for ELPA. That is, use # "jabber" instead of "emacs-jabber" as base name. CLEANFILES = sha1.elc hex-util.elc jabber-pkg.el dist_lisp_LISP = $(my_lisp_sources) $(compat_lisp_sources) jabber-autoloads.el jabber-ourversion.el MAINTAINERCLEANFILES = jabber-autoloads.el EXTRA_DIST = jabber-pkg.el.in info_TEXINFOS = jabber.texi dist_libexec_SCRIPTS = emacs-jabber-uri-handler SUBDIRS = . tests $(am__append_3) all: all-recursive .SUFFIXES: .SUFFIXES: .dvi .html .info .pdf .ps .texi am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ cd $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) cd $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) jabber-ourversion.el: $(top_builddir)/config.status $(srcdir)/jabber-ourversion.el.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-dist_libexecSCRIPTS: $(dist_libexec_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" @list='$(dist_libexec_SCRIPTS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f $$d$$p; then \ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ echo " $(dist_libexecSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(libexecdir)/$$f'"; \ $(dist_libexecSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(libexecdir)/$$f"; \ else :; fi; \ done uninstall-dist_libexecSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_libexec_SCRIPTS)'; for p in $$list; do \ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ echo " rm -f '$(DESTDIR)$(libexecdir)/$$f'"; \ rm -f "$(DESTDIR)$(libexecdir)/$$f"; \ done .texi.info: restore=: && backupdir="$(am__leading_dot)am$$$$" && \ am__cwd=`pwd` && cd $(srcdir) && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ cd "$$am__cwd"; \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ $<; \ then \ rc=0; \ cd $(srcdir); \ else \ rc=$$?; \ cd $(srcdir) && \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc .texi.dvi: TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $< .texi.pdf: TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $< .texi.html: rm -rf $(@:.html=.htp) if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) $<; \ then \ rm -rf $@; \ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \ else \ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \ exit 1; \ fi $(srcdir)/jabber.info: jabber.texi jabber.dvi: jabber.texi jabber.pdf: jabber.texi jabber.html: jabber.texi .dvi.ps: TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(DVIPS) -o $@ $< uninstall-dvi-am: @$(NORMAL_UNINSTALL) @list='$(DVIS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ rm -f "$(DESTDIR)$(dvidir)/$$f"; \ done uninstall-html-am: @$(NORMAL_UNINSTALL) @list='$(HTMLS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ done uninstall-info-am: @$(PRE_UNINSTALL) @if test -d '$(DESTDIR)$(infodir)' && \ (install-info --version && \ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ done; \ else :; fi @$(NORMAL_UNINSTALL) @list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ else :; fi); \ done uninstall-pdf-am: @$(NORMAL_UNINSTALL) @list='$(PDFS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ done uninstall-ps-am: @$(NORMAL_UNINSTALL) @list='$(PSS)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ rm -f "$(DESTDIR)$(psdir)/$$f"; \ done dist-info: $(INFO_DEPS) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; \ for base in $$list; do \ case $$base in \ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$base; then d=.; else d=$(srcdir); fi; \ base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ if test -f $$file; then \ relfile=`expr "$$file" : "$$d/\(.*\)"`; \ test -f $(distdir)/$$relfile || \ cp -p $$file $(distdir)/$$relfile; \ else :; fi; \ done; \ done mostlyclean-aminfo: -rm -rf jabber.aux jabber.cp jabber.cps jabber.fn jabber.fns jabber.ky \ jabber.kys jabber.log jabber.pg jabber.pgs jabber.tmp \ jabber.toc jabber.tp jabber.tps jabber.vr jabber.vrs \ jabber.dvi jabber.pdf jabber.ps jabber.html maintainer-clean-aminfo: @list='$(INFO_DEPS)'; for i in $$list; do \ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ done elc-stamp: $(LISP) @echo 'WARNING: Warnings can be ignored. :-)' @rm -f elc-temp && touch elc-temp if test "$(EMACS)" != no; then \ set x; \ list='$(LISP)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ set x "$$@" "$$d$$p"; shift; \ done; \ shift; \ EMACS="$(EMACS)" $(SHELL) $(elisp_comp) "$$@" || exit 1; \ else : ; fi @mv -f elc-temp $@ $(am__ELCFILES): elc-stamp @if test "$(EMACS)" != no && test ! -f $@; then \ trap 'rm -rf elc-lock elc-stamp' 1 2 13 15; \ if mkdir elc-lock 2>/dev/null; then \ rm -f elc-stamp; \ $(MAKE) $(AM_MAKEFLAGS) elc-stamp; \ rmdir elc-lock; \ else \ while test -d elc-lock; do sleep 1; done; \ test -f elc-stamp; exit $$?; \ fi; \ else : ; fi install-dist_lispLISP: $(dist_lisp_LISP) $(ELCFILES) @$(NORMAL_INSTALL) @if test "$(EMACS)" != no; then \ test -z "$(lispdir)" || $(MKDIR_P) "$(DESTDIR)$(lispdir)"; \ list='$(dist_lisp_LISP)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(dist_lispLISP_INSTALL) '$$d$$p' '$(DESTDIR)$(lispdir)/$$f'"; \ $(dist_lispLISP_INSTALL) "$$d$$p" "$(DESTDIR)$(lispdir)/$$f"; \ if test -f $${p}c; then \ echo " $(dist_lispLISP_INSTALL) '$${p}c' '$(DESTDIR)$(lispdir)/$${f}c'"; \ $(dist_lispLISP_INSTALL) "$${p}c" "$(DESTDIR)$(lispdir)/$${f}c"; \ else : ; fi; \ done; \ else : ; fi uninstall-dist_lispLISP: @$(NORMAL_UNINSTALL) @if test "$(EMACS)" != no; then \ list='$(dist_lisp_LISP)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(lispdir)/$$f' '$(DESTDIR)$(lispdir)/$${f}c'"; \ rm -f "$(DESTDIR)$(lispdir)/$$f" "$(DESTDIR)$(lispdir)/$${f}c"; \ done; \ else : ; fi clean-lisp: -rm -f elc-stamp $(ELCFILES) # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. # To change the values of `make' variables: instead of editing Makefiles, # (1) if the variable is set in `config.status', edit `config.status' # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" $(RECURSIVE_CLEAN_TARGETS): @failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ rev=''; for subdir in $$list; do \ if test "$$subdir" = "."; then :; else \ rev="$$subdir $$rev"; \ fi; \ done; \ rev="$$rev ."; \ target=`echo $@ | sed s/-recursive//`; \ for subdir in $$rev; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d $(distdir) || mkdir $(distdir) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ am__remove_distdir=: \ am__skip_length_check=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-info -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(INFO_DEPS) $(SCRIPTS) $(LISP) $(ELCFILES) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(lispdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-lisp mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: $(DVIS) html: html-recursive html-am: $(HTMLS) info: info-recursive info-am: $(INFO_DEPS) install-data-am: install-dist_lispLISP install-info-am install-dvi: install-dvi-recursive install-dvi-am: $(DVIS) @$(NORMAL_INSTALL) test -z "$(dvidir)" || $(MKDIR_P) "$(DESTDIR)$(dvidir)" @list='$(DVIS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(dvidir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(dvidir)/$$f"; \ done install-exec-am: install-dist_libexecSCRIPTS install-html: install-html-recursive install-html-am: $(HTMLS) @$(NORMAL_INSTALL) test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)" @list='$(HTMLS)'; for p in $$list; do \ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ if test -d "$$d$$p"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \ else \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ fi; \ done install-info: install-info-recursive install-info-am: $(INFO_DEPS) @$(NORMAL_INSTALL) test -z "$(infodir)" || $(MKDIR_P) "$(DESTDIR)$(infodir)" @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; \ for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$file; then d=.; else d=$(srcdir); fi; \ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ if test -f $$ifile; then \ relfile=`echo "$$ifile" | sed 's|^.*/||'`; \ echo " $(INSTALL_DATA) '$$ifile' '$(DESTDIR)$(infodir)/$$relfile'"; \ $(INSTALL_DATA) "$$ifile" "$(DESTDIR)$(infodir)/$$relfile"; \ else : ; fi; \ done; \ done @$(POST_INSTALL) @if (install-info --version && \ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ done; \ else : ; fi install-man: install-pdf: install-pdf-recursive install-pdf-am: $(PDFS) @$(NORMAL_INSTALL) test -z "$(pdfdir)" || $(MKDIR_P) "$(DESTDIR)$(pdfdir)" @list='$(PDFS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/$$f"; \ done install-ps: install-ps-recursive install-ps-am: $(PSS) @$(NORMAL_INSTALL) test -z "$(psdir)" || $(MKDIR_P) "$(DESTDIR)$(psdir)" @list='$(PSS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(psdir)/$$f'"; \ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(psdir)/$$f"; \ done installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-aminfo \ maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-aminfo mostlyclean-generic pdf: pdf-recursive pdf-am: $(PDFS) ps: ps-recursive ps-am: $(PSS) uninstall-am: uninstall-dist_libexecSCRIPTS uninstall-dist_lispLISP \ uninstall-dvi-am uninstall-html-am uninstall-info-am \ uninstall-pdf-am uninstall-ps-am .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ install-strip .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ clean-lisp ctags ctags-recursive dist dist-all dist-bzip2 \ dist-gzip dist-info dist-lzma dist-shar dist-tarZ dist-zip \ distcheck distclean distclean-generic distclean-tags \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_libexecSCRIPTS \ install-dist_lispLISP install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-aminfo maintainer-clean-generic mostlyclean \ mostlyclean-aminfo mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-recursive uninstall uninstall-am \ uninstall-dist_libexecSCRIPTS uninstall-dist_lispLISP \ uninstall-dvi-am uninstall-html-am uninstall-info-am \ uninstall-pdf-am uninstall-ps-am # The autoload file will cause Lisp sources to be rebuilt _twice_: the # timestamp of the Lisp compilation is set _before_ the autoloads are # regenerated, which means that jabber-autoload.el is once again # considered new, which means that everything will be built again. # Suggestions welcome. # # Emacs 21 requires that the file already exist and have non-zero # size, so we touch it with ancient timestamp. jabber-autoloads.el: $(my_lisp_sources) test -s $@ || cp -f $(srcdir)/jabber-autoloads.stub $@; touch -t 197001030000 $@ $(EMACS) --batch --eval "(setq generated-autoload-file \"$(abs_builddir)/$@\")" -f batch-update-autoloads $(srcdir) elpa: dist rm -rf emacs-jabber-$(PACKAGE_VERSION) jabber-$(PACKAGE_VERSION) $(AMTAR) xzf emacs-jabber-$(PACKAGE_VERSION).tar.gz mv emacs-jabber-$(PACKAGE_VERSION) jabber-$(PACKAGE_VERSION) cd jabber-$(PACKAGE_VERSION) ; install-info jabber.info dir sed "s/@""PACKAGE_VERSION@""/$(PACKAGE_VERSION)/" < $(srcdir)/jabber-pkg.el.in > jabber-$(PACKAGE_VERSION)/jabber-pkg.el $(AMTAR) chf jabber-$(PACKAGE_VERSION).tar jabber-$(PACKAGE_VERSION) rm -rf jabber-$(PACKAGE_VERSION) @echo "Created jabber-$(PACKAGE_VERSION).tar" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: emacs-jabber-0.8.0/jabber-ourversion.el.in0000644000175100017510000000032411133727374015351 00000000000000;; @configure_input@ ;; This value gets updated automatically when configure.ac is changed. (defconst jabber-version "@PACKAGE_VERSION@" "version returned to those who query us") (provide 'jabber-ourversion) emacs-jabber-0.8.0/configure0000755000175100017510000030665211252667704012712 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61 for jabber.el 0.8.0. # # Report bugs to . # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) as_nl=' ' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH if test "x$CONFIG_SHELL" = x; then if (eval ":") 2>/dev/null; then as_have_required=yes else as_have_required=no fi if test $as_have_required = yes && (eval ": (as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=\$LINENO as_lineno_2=\$LINENO test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ") 2> /dev/null; then : else as_candidate_shells= as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. case $as_dir in /*) for as_base in sh bash ksh sh5; do as_candidate_shells="$as_candidate_shells $as_dir/$as_base" done;; esac done IFS=$as_save_IFS for as_shell in $as_candidate_shells $SHELL; do # Try only shells that exist, to save several forks. if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { ("$as_shell") 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : _ASEOF }; then CONFIG_SHELL=$as_shell as_have_required=yes if { "$as_shell" 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : (as_func_return () { (exit $1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = "$1" ); then : else exitcode=1 echo positional parameters were not saved. fi test $exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } _ASEOF }; then break fi fi done if test "x$CONFIG_SHELL" != x; then for as_var in BASH_ENV ENV do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test $as_have_required = no; then echo This script requires a shell more modern than all the echo shells that I found on your system. Please install a echo modern shell, or manually run the script under such a echo shell if you do have one. { (exit 1); exit 1; } fi fi fi (eval "as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0") || { echo No shell found that supports shell functions. echo Please tell autoconf@gnu.org about your system, echo including any error possibly output before this echo message } as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir fi echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='jabber.el' PACKAGE_TARNAME='emacs-jabber' PACKAGE_VERSION='0.8.0' PACKAGE_STRING='jabber.el 0.8.0' PACKAGE_BUGREPORT='emacs-jabber-general@lists.sourceforge.net' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datarootdir datadir sysconfdir sharedstatedir localstatedir includedir oldincludedir docdir infodir htmldir dvidir pdfdir psdir libdir localedir mandir DEFS ECHO_C ECHO_N ECHO_T LIBS build_alias host_alias target_alias INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA am__isrc CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar EMACS EMACSLOADPATH lispdir USE_OUR_SHA1_TRUE USE_OUR_SHA1_FALSE USE_OUR_HEX_UTIL_TRUE USE_OUR_HEX_UTIL_FALSE GCONFTOOL USE_GCONFTOOL_TRUE USE_GCONFTOOL_FALSE GCONF_SCHEMA_CONFIG_SOURCE GCONF_SCHEMA_FILE_DIR GCONF_SCHEMAS_INSTALL_TRUE GCONF_SCHEMAS_INSTALL_FALSE LIBOBJS LTLIBOBJS' ac_subst_files='' ac_precious_vars='build_alias host_alias target_alias EMACS EMACSLOADPATH' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` eval enable_$ac_feature=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` eval enable_$ac_feature=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/[-.]/_/g'` eval with_$ac_package=\$ac_optarg ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/[-.]/_/g'` eval with_$ac_package=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute directory names. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; } done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || { echo "$as_me: error: Working directory cannot be determined" >&2 { (exit 1); exit 1; }; } test "X$ac_ls_di" = "X$ac_pwd_ls_di" || { echo "$as_me: error: pwd does not report name of working directory" >&2 { (exit 1); exit 1; }; } # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$0" || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 { (exit 1); exit 1; }; } pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures jabber.el 0.8.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/emacs-jabber] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of jabber.el 0.8.0:";; esac cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-schemas-install Disable the schemas installation Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-lispdir override the default lisp directory --with-gconf-source=sourceaddress Config database for installing schema files. --with-gconf-schema-file-dir=dir Directory for installing schema files. Some influential environment variables: EMACS the Emacs editor command EMACSLOADPATH the Emacs library search path Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF jabber.el configure 0.8.0 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by jabber.el $as_me 0.8.0, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then set x "$CONFIG_SITE" elif test "x$prefix" != xNONE; then set x "$prefix/share/config.site" "$prefix/etc/config.site" else set x "$ac_default_prefix/share/config.site" \ "$ac_default_prefix/etc/config.site" fi shift for ac_site_file do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.10' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} { (exit 1); exit 1; }; } fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. { echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done IFS=$as_save_IFS fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { echo "$as_me:$LINENO: checking whether build environment is sane" >&5 echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&5 echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&2;} { (exit 1); exit 1; }; } fi test "$2" = conftest.file ) then # Ok. : else { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! Check your system clock" >&5 echo "$as_me: error: newly created file is older than distributed files! Check your system clock" >&2;} { (exit 1); exit 1; }; } fi { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. echo might interpret backslashes. # By default was `s,x,x', remove it if useless. cat <<\_ACEOF >conftest.sed s/[\\$]/&&/g;s/;s,x,x,$// _ACEOF program_transform_name=`echo $program_transform_name | sed -f conftest.sed` rm -f conftest.sed # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi { echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } if test -z "$MKDIR_P"; then if test "${ac_cv_path_mkdir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. test -d ./--version && rmdir ./--version MKDIR_P="$ac_install_sh -d" fi fi { echo "$as_me:$LINENO: result: $MKDIR_P" >&5 echo "${ECHO_T}$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_AWK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { echo "$as_me:$LINENO: result: $AWK" >&5 echo "${ECHO_T}$AWK" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$AWK" && break done { echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6; } SET_MAKE= else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} { (exit 1); exit 1; }; } fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='emacs-jabber' VERSION='0.8.0' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { echo "$as_me:$LINENO: result: $STRIP" >&5 echo "${ECHO_T}$STRIP" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRIP="strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 echo "${ECHO_T}$ac_ct_STRIP" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&5 echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools whose name does not start with the host triplet. If you think this configuration is useful to you, please write to autoconf@gnu.org." >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' # If set to t, that means we are running in a shell under Emacs. # If you have an Emacs named "t", then use the full path. test x"$EMACS" = xt && EMACS= for ac_prog in emacs xemacs do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_EMACS+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$EMACS"; then ac_cv_prog_EMACS="$EMACS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_EMACS="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi EMACS=$ac_cv_prog_EMACS if test -n "$EMACS"; then { echo "$as_me:$LINENO: result: $EMACS" >&5 echo "${ECHO_T}$EMACS" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi test -n "$EMACS" && break done test -n "$EMACS" || EMACS="no" # Check whether --with-lispdir was given. if test "${with_lispdir+set}" = set; then withval=$with_lispdir; lispdir="$withval" { echo "$as_me:$LINENO: checking where .elc files should go" >&5 echo $ECHO_N "checking where .elc files should go... $ECHO_C" >&6; } { echo "$as_me:$LINENO: result: $lispdir" >&5 echo "${ECHO_T}$lispdir" >&6; } else { echo "$as_me:$LINENO: checking where .elc files should go" >&5 echo $ECHO_N "checking where .elc files should go... $ECHO_C" >&6; } if test "${am_cv_lispdir+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test $EMACS != "no"; then if test x${lispdir+set} != xset; then # If $EMACS isn't GNU Emacs or XEmacs, this can blow up pretty badly # Some emacsen will start up in interactive mode, requiring C-x C-c to exit, # which is non-obvious for non-emacs users. # Redirecting /dev/null should help a bit; pity we can't detect "broken" # emacsen earlier and avoid running this altogether. { (echo "$as_me:$LINENO: \$EMACS -batch -q -eval '(while load-path (princ (concat (car load-path) \"\\n\")) (setq load-path (cdr load-path)))' conftest.out") >&5 ($EMACS -batch -q -eval '(while load-path (princ (concat (car load-path) "\n")) (setq load-path (cdr load-path)))' conftest.out) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } am_cv_lispdir=`sed -n \ -e 's,/$,,' \ -e '/.*\/lib\/x*emacs\/site-lisp$/{s,.*/lib/\(x*emacs/site-lisp\)$,${libdir}/\1,;p;q;}' \ -e '/.*\/share\/x*emacs\/site-lisp$/{s,.*/share/\(x*emacs/site-lisp\),${datarootdir}/\1,;p;q;}' \ conftest.out` rm conftest.out fi fi test -z "$am_cv_lispdir" && am_cv_lispdir='${datadir}/emacs/site-lisp' fi { echo "$as_me:$LINENO: result: $am_cv_lispdir" >&5 echo "${ECHO_T}$am_cv_lispdir" >&6; } lispdir="$am_cv_lispdir" fi if test "$EMACS" = no; then { { echo "$as_me:$LINENO: error: cannot find Emacs" >&5 echo "$as_me: error: cannot find Emacs" >&2;} { (exit 1); exit 1; }; } fi { echo "$as_me:$LINENO: checking whether $EMACS has library sha1" >&5 echo $ECHO_N "checking whether $EMACS has library sha1... $ECHO_C" >&6; } if test "${ax_cv_emacs_lib_sha1+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.el <&5 ($EMACS -batch -l conftest.el) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } if test $ac_status -eq 0; then ax_cv_emacs_lib_sha1=yes else ax_cv_emacs_lib_sha1=no fi fi { echo "$as_me:$LINENO: result: $ax_cv_emacs_lib_sha1" >&5 echo "${ECHO_T}$ax_cv_emacs_lib_sha1" >&6; } if test $ax_cv_emacs_lib_sha1 = yes; then HAVE_SHA1=yes else HAVE_SHA1=no fi { echo "$as_me:$LINENO: checking whether $EMACS has library sha1-el" >&5 echo $ECHO_N "checking whether $EMACS has library sha1-el... $ECHO_C" >&6; } if test "${ax_cv_emacs_lib_sha1_el+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.el <&5 ($EMACS -batch -l conftest.el) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } if test $ac_status -eq 0; then ax_cv_emacs_lib_sha1_el=yes else ax_cv_emacs_lib_sha1_el=no fi fi { echo "$as_me:$LINENO: result: $ax_cv_emacs_lib_sha1_el" >&5 echo "${ECHO_T}$ax_cv_emacs_lib_sha1_el" >&6; } if test $ax_cv_emacs_lib_sha1_el = yes; then HAVE_SHA1_EL=yes else HAVE_SHA1_EL=no fi { echo "$as_me:$LINENO: checking whether $EMACS has library hex-util" >&5 echo $ECHO_N "checking whether $EMACS has library hex-util... $ECHO_C" >&6; } if test "${ax_cv_emacs_lib_hex_util+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.el <&5 ($EMACS -batch -l conftest.el) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } if test $ac_status -eq 0; then ax_cv_emacs_lib_hex_util=yes else ax_cv_emacs_lib_hex_util=no fi fi { echo "$as_me:$LINENO: result: $ax_cv_emacs_lib_hex_util" >&5 echo "${ECHO_T}$ax_cv_emacs_lib_hex_util" >&6; } if test $ax_cv_emacs_lib_hex_util = yes; then HAVE_HEX_UTIL=yes else HAVE_HEX_UTIL=no fi if test x$HAVE_SHA1 = xno -a x$HAVE_SHA1_EL = xno; then USE_OUR_SHA1_TRUE= USE_OUR_SHA1_FALSE='#' else USE_OUR_SHA1_TRUE='#' USE_OUR_SHA1_FALSE= fi if test x$HAVE_HEX_UTIL = xno; then USE_OUR_HEX_UTIL_TRUE= USE_OUR_HEX_UTIL_FALSE='#' else USE_OUR_HEX_UTIL_TRUE='#' USE_OUR_HEX_UTIL_FALSE= fi # Extract the first word of "gconftool-2", so it can be a program name with args. set dummy gconftool-2; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_path_GCONFTOOL+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $GCONFTOOL in [\\/]* | ?:[\\/]*) ac_cv_path_GCONFTOOL="$GCONFTOOL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_GCONFTOOL="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_GCONFTOOL" && ac_cv_path_GCONFTOOL="no" ;; esac fi GCONFTOOL=$ac_cv_path_GCONFTOOL if test -n "$GCONFTOOL"; then { echo "$as_me:$LINENO: result: $GCONFTOOL" >&5 echo "${ECHO_T}$GCONFTOOL" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } fi if test "x$GCONFTOOL" != "xno"; then USE_GCONFTOOL_TRUE= USE_GCONFTOOL_FALSE='#' else USE_GCONFTOOL_TRUE='#' USE_GCONFTOOL_FALSE= fi if test "x$GCONF_SCHEMA_INSTALL_SOURCE" = "x"; then GCONF_SCHEMA_CONFIG_SOURCE=`gconftool-2 --get-default-source` else GCONF_SCHEMA_CONFIG_SOURCE=$GCONF_SCHEMA_INSTALL_SOURCE fi # Check whether --with-gconf-source was given. if test "${with_gconf_source+set}" = set; then withval=$with_gconf_source; GCONF_SCHEMA_CONFIG_SOURCE="$withval" fi { echo "$as_me:$LINENO: result: Using config source $GCONF_SCHEMA_CONFIG_SOURCE for schema installation" >&5 echo "${ECHO_T}Using config source $GCONF_SCHEMA_CONFIG_SOURCE for schema installation" >&6; } if test "x$GCONF_SCHEMA_FILE_DIR" = "x"; then GCONF_SCHEMA_FILE_DIR='$(sysconfdir)/gconf/schemas' fi # Check whether --with-gconf-schema-file-dir was given. if test "${with_gconf_schema_file_dir+set}" = set; then withval=$with_gconf_schema_file_dir; GCONF_SCHEMA_FILE_DIR="$withval" fi { echo "$as_me:$LINENO: result: Using $GCONF_SCHEMA_FILE_DIR as install directory for schema files" >&5 echo "${ECHO_T}Using $GCONF_SCHEMA_FILE_DIR as install directory for schema files" >&6; } # Check whether --enable-schemas-install was given. if test "${enable_schemas_install+set}" = set; then enableval=$enable_schemas_install; case ${enableval} in yes|no) ;; *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-schemas-install" >&5 echo "$as_me: error: bad value ${enableval} for --enable-schemas-install" >&2;} { (exit 1); exit 1; }; } ;; esac fi if test "$enable_schemas_install" != no; then GCONF_SCHEMAS_INSTALL_TRUE= GCONF_SCHEMAS_INSTALL_FALSE='#' else GCONF_SCHEMAS_INSTALL_TRUE='#' GCONF_SCHEMAS_INSTALL_FALSE= fi ac_config_files="$ac_config_files Makefile tests/Makefile gconf/Makefile jabber-ourversion.el" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { echo "$as_me:$LINENO: updating cache $cache_file" >&5 echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -z "${USE_OUR_SHA1_TRUE}" && test -z "${USE_OUR_SHA1_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"USE_OUR_SHA1\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"USE_OUR_SHA1\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${USE_OUR_HEX_UTIL_TRUE}" && test -z "${USE_OUR_HEX_UTIL_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"USE_OUR_HEX_UTIL\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"USE_OUR_HEX_UTIL\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${USE_GCONFTOOL_TRUE}" && test -z "${USE_GCONFTOOL_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"USE_GCONFTOOL\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"USE_GCONFTOOL\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi if test -z "${GCONF_SCHEMAS_INSTALL_TRUE}" && test -z "${GCONF_SCHEMAS_INSTALL_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"GCONF_SCHEMAS_INSTALL\" was never defined. Usually this means the macro was only invoked conditionally." >&5 echo "$as_me: error: conditional \"GCONF_SCHEMAS_INSTALL\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) as_nl=' ' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir fi echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by jabber.el $as_me 0.8.0, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ jabber.el config.status 0.8.0 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2006 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 CONFIG_SHELL=$SHELL export CONFIG_SHELL exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; "gconf/Makefile") CONFIG_FILES="$CONFIG_FILES gconf/Makefile" ;; "jabber-ourversion.el") CONFIG_FILES="$CONFIG_FILES jabber-ourversion.el" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } # # Set up the sed scripts for CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "$CONFIG_FILES"; then _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF SHELL!$SHELL$ac_delim PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim PACKAGE_NAME!$PACKAGE_NAME$ac_delim PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim PACKAGE_STRING!$PACKAGE_STRING$ac_delim PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim exec_prefix!$exec_prefix$ac_delim prefix!$prefix$ac_delim program_transform_name!$program_transform_name$ac_delim bindir!$bindir$ac_delim sbindir!$sbindir$ac_delim libexecdir!$libexecdir$ac_delim datarootdir!$datarootdir$ac_delim datadir!$datadir$ac_delim sysconfdir!$sysconfdir$ac_delim sharedstatedir!$sharedstatedir$ac_delim localstatedir!$localstatedir$ac_delim includedir!$includedir$ac_delim oldincludedir!$oldincludedir$ac_delim docdir!$docdir$ac_delim infodir!$infodir$ac_delim htmldir!$htmldir$ac_delim dvidir!$dvidir$ac_delim pdfdir!$pdfdir$ac_delim psdir!$psdir$ac_delim libdir!$libdir$ac_delim localedir!$localedir$ac_delim mandir!$mandir$ac_delim DEFS!$DEFS$ac_delim ECHO_C!$ECHO_C$ac_delim ECHO_N!$ECHO_N$ac_delim ECHO_T!$ECHO_T$ac_delim LIBS!$LIBS$ac_delim build_alias!$build_alias$ac_delim host_alias!$host_alias$ac_delim target_alias!$target_alias$ac_delim INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim INSTALL_DATA!$INSTALL_DATA$ac_delim am__isrc!$am__isrc$ac_delim CYGPATH_W!$CYGPATH_W$ac_delim PACKAGE!$PACKAGE$ac_delim VERSION!$VERSION$ac_delim ACLOCAL!$ACLOCAL$ac_delim AUTOCONF!$AUTOCONF$ac_delim AUTOMAKE!$AUTOMAKE$ac_delim AUTOHEADER!$AUTOHEADER$ac_delim MAKEINFO!$MAKEINFO$ac_delim install_sh!$install_sh$ac_delim STRIP!$STRIP$ac_delim INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim mkdir_p!$mkdir_p$ac_delim AWK!$AWK$ac_delim SET_MAKE!$SET_MAKE$ac_delim am__leading_dot!$am__leading_dot$ac_delim AMTAR!$AMTAR$ac_delim am__tar!$am__tar$ac_delim am__untar!$am__untar$ac_delim EMACS!$EMACS$ac_delim EMACSLOADPATH!$EMACSLOADPATH$ac_delim lispdir!$lispdir$ac_delim USE_OUR_SHA1_TRUE!$USE_OUR_SHA1_TRUE$ac_delim USE_OUR_SHA1_FALSE!$USE_OUR_SHA1_FALSE$ac_delim USE_OUR_HEX_UTIL_TRUE!$USE_OUR_HEX_UTIL_TRUE$ac_delim USE_OUR_HEX_UTIL_FALSE!$USE_OUR_HEX_UTIL_FALSE$ac_delim GCONFTOOL!$GCONFTOOL$ac_delim USE_GCONFTOOL_TRUE!$USE_GCONFTOOL_TRUE$ac_delim USE_GCONFTOOL_FALSE!$USE_GCONFTOOL_FALSE$ac_delim GCONF_SCHEMA_CONFIG_SOURCE!$GCONF_SCHEMA_CONFIG_SOURCE$ac_delim GCONF_SCHEMA_FILE_DIR!$GCONF_SCHEMA_FILE_DIR$ac_delim GCONF_SCHEMAS_INSTALL_TRUE!$GCONF_SCHEMAS_INSTALL_TRUE$ac_delim GCONF_SCHEMAS_INSTALL_FALSE!$GCONF_SCHEMAS_INSTALL_FALSE$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 75; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` if test -n "$ac_eof"; then ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` ac_eof=`expr $ac_eof + 1` fi cat >>$CONFIG_STATUS <<_ACEOF cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof /@[a-zA-Z_][a-zA-Z_0-9]*@/!b end _ACEOF sed ' s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g s/^/s,@/; s/!/@,|#_!!_#|/ :n t n s/'"$ac_delim"'$/,g/; t s/$/\\/; p N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n ' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF :end s/|#_!!_#|//g CEOF$ac_eof _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF fi # test -n "$CONFIG_FILES" for ac_tag in :F $CONFIG_FILES do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 echo "$as_me: error: Invalid tag $ac_tag." >&2;} { (exit 1); exit 1; }; };; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 echo "$as_me: error: cannot find input file: $ac_f" >&2;} { (exit 1); exit 1; }; };; esac ac_file_inputs="$ac_file_inputs $ac_f" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input="Generated from "`IFS=: echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} fi case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin";; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir="$ac_dir" case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= case `sed -n '/datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p ' $ac_file_inputs` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s&@configure_input@&$configure_input&;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out"; rm -f "$tmp/out";; *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; esac ;; esac done # for ac_tag { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi emacs-jabber-0.8.0/AUTHORS0000644000175100017510000000065711133727374012045 00000000000000Developers: Tom Berger Magnus Henoch Kirill A. Korinskiy Detlev Zundel Evgenii Terechkov Contributors: Anthony Chaumas-Pellet Mathias Dahl Mario Domenech Goulart Nolan Eakins Ami Fischman François Fleuret David Hansen Rodrigo Lazo Justin Kirby Carl Henrik Lunde Olivier Ramonat Andrey Slusar Valery V. Vorotyntsev Milan Zamazal Xavier Maillard Vitaly Mayatskikh Alexander Solovyov arch-tag: 15700144-3BD9-11D9-871C-000A95C2FCD0 emacs-jabber-0.8.0/NEWS0000644000175100017510000001151211252721310011446 00000000000000-*- mode: outline -*- * New features in jabber.el 0.8 ** Support for multiple accounts Configuration variables have changed. See section "Account settings" in the manual. ** Activity mode improved Customizable face for personal messages added, list of unwanted (banned) JIDs added ** Simple automatic answering machine Realized as alert. Can match regexp and answer with predefined string ** OSD alerts (message, MUC, MUC-personal) ** Family of personal MUC alerts added See section "Standard alerts" in manual. ** MUC nicks completion See section "Groupchat" in manual. ** Automatic reconnection Not enabled by default; See "Reconnecting" section in manual. ** Support for XEP-0085 This means "contact is typing" notifications when chatting with Gajim or Google Talk users, among others. See "Typing notifications" section in the manual. ** Option: hide offline contacts in roster See "The roster buffer" in manual. ** Clean history from chat buffers See jabber-truncate-* functions and new options for jabber-alert-muc-hooks and jabber-alert-message-hooks. See section "Message history" in manual too. ** MUC bookmarks See jabber-edit-bookmarks function and "Bookmarks" section in manual. ** Name of browse buffers customizable See "Services" section in manual. ** Subscription requests are sent to chat buffers Subscription requests now displayed in chat buffers. See "Presence subscription" section in manual. ** Option: hide avatar in chat buffer `jabber-chat-buffer-show-avatar'. ** Gmail notifications (Not documented nor autoloaded) ** GConf-based installation of URI handler See "XMPP URIs" in manual. * New features in jabber.el 0.7.1 ** STARTTLS ** SRV records Requires No Gnus. ** Message composition buffer Try jabber-compose. ** XMPP URIs are handled See manual for setup. ** Autoaway ** MUC features *** Don't display alerts for your own messages See jabber-muc-alert-self. *** Presence changes are sent to MUC rooms too *** Check room features before joining ** Avatars Viewing and publishing JEP-0153 avatars (vCard-based) is now supported. ** File transfer ** Sound files per contact for alerts ** Per-user history files changed For some time after 0.7 these file names erroneously contained double quotes. If you have used the CVS version you'll need to rename your history files manually. ** New function: jabber-send-directed-presence ** Entity time supported (XEP-0090) ** Last activity supported (XEP-0012) * New features in jabber.el 0.7 ** SSL connections possible See variable `jabber-connection-type'. ** Chat buffers rewritten New modular design gives increased extensibility. *** Received URLs are displayed *** Long lines are filled See jabber-chat-fill-long-lines. *** Rare timestamps are printed by default See jabber-print-rare-time and jabber-rare-time-format. ** MUC features *** Different default nicknames for different MUC rooms See jabber-muc-default-nicknames. *** Autojoin MUC rooms on connection See jabber-muc-autojoin. *** Change nickname Actually simply an alias from jabber-muc-nick to jabber-groupchat-join. *** Invitations Both sending and receiving invitiations is supported. *** Basic affiliation change support (Not finished) *** Private MUC messages *** Support for setting and displaying topic ** Global key bindings Global keymap under C-x C-j. ** Vcard viewer and editor ** Roster export ** Message events (JEP-0022) ** Easy way to define external notifiers See define-jabber-alert. Alerts for Festival (speech synthesis), Sawfish, and xmessage added. ** Activity mode improved Can now display count in frame title. Update hook added. ** Roster display optimized ** Optionally use per-contact history files ** Jabber menu in menubar not enabled by default Call jabber-menu to have it there. ** Flyspell in chat buffers Flyspell will only spell check what you're currently writing. ** Different time formats for instant and delayed messages See `jabber-chat-time-format' and `jabber-chat-delayed-time-format'. You can see the complete timestamp in a tooltip by holding the mouse over the prompt. ** Chat buffers in inactive windows are scrolled ** Roster is sorted by name also * New features in jabber.el 0.6.1 ** Message history Set jabber-history-enabled to t to activate it. ** Backlogs If you have history enabled, the last few messages are inserted when you open a new chat buffer. ** Activity tracking on the mode line Activate it with M-x jabber-activity-mode. ** Receive an alert when a specific person goes online Use it with M-x jabber-watch-add. ** Support for /me in chats As in "/me laughs" etc. ** Message alerts for current buffer can be disabled Set jabber-message-alert-same-buffer to nil to do that. ** Basic moderation support in MUC ** MUC alerts are separated from ordinary message alerts Customize jabber-alert-muc-hooks to get your desired behaviour. arch-tag: 1CE20E4E-3BD9-11D9-8D64-000A95C2FCD0 emacs-jabber-0.8.0/elisp-comp0000755000175100017510000000523011252667715012767 00000000000000#!/bin/sh # Copyright (C) 1995, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. scriptversion=2005-05-14.22 # Franc,ois Pinard , 1995. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case $1 in '') echo "$0: No files. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: elisp-comp [--help] [--version] FILES... This script byte-compiles all `.el' files listed as FILES using GNU Emacs, and put the resulting `.elc' files into the current directory, so disregarding the original directories used in `.el' arguments. This script manages in such a way that all Emacs LISP files to be compiled are made visible between themselves, in the event they require or load-library one another. Report bugs to . EOF exit $? ;; -v | --v*) echo "elisp-comp $scriptversion" exit $? ;; esac if test -z "$EMACS" || test "$EMACS" = "t"; then # Value of "t" means we are running in a shell under Emacs. # Just assume Emacs is called "emacs". EMACS=emacs fi tempdir=elc.$$ # Cleanup the temporary directory on exit. trap 'ret=$?; rm -rf "$tempdir" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 mkdir $tempdir cp "$@" $tempdir ( cd $tempdir echo "(setq load-path (cons nil load-path))" > script $EMACS -batch -q -l script -f batch-byte-compile *.el || exit $? mv *.elc .. ) || exit $? (exit 0); exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: emacs-jabber-0.8.0/install-sh0000755000175100017510000003246411252667706013006 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-12-25.00 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: emacs-jabber-0.8.0/missing0000755000175100017510000002557711252667706012410 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2006-05-10.23 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case $1 in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $1 in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG="\${$#}" case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case $firstarg in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case $firstarg in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: emacs-jabber-0.8.0/texinfo.tex0000644000175100017510000105275711252667714013207 00000000000000% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2007-12-02.17} % % Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, 2007, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, % 2007 Free Software Foundation, Inc. % % This texinfo.tex file is free software: you can redistribute it and/or % modify it under the terms of the GNU General Public License as % published by the Free Software Foundation, either version 3 of the % License, or (at your option) any later version. % % This texinfo.tex file is distributed in the hope that it will be % useful, but WITHOUT ANY WARRANTY; without even the implied warranty % of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU % General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program. If not, see . % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. (This has been our intent since Texinfo was invented.) % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://www.gnu.org/software/texinfo/ (the Texinfo home page), or % ftp://tug.org/tex/texinfo.tex % (and all CTAN mirrors, see http://www.ctan.org). % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexstar=\* \let\ptext=\t % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Since the category of space is not known, we have to be careful. \chardef\spacecat = 10 \def\spaceisspace{\catcode`\ =\spacecat} % sometimes characters are active, so we need control sequences. \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dashChar = `\- \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\lquoteChar= `\` \chardef\questChar = `\? \chardef\rquoteChar= `\' \chardef\semiChar = `\; \chardef\underChar = `\_ % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt} % @| inserts a changebar to the left of the current line. It should % surround any changed text. This approach does *not* work if the % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). % \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode % % Append this vertical mode material after the current line in the output. \vadjust{% % We want to insert a rule with the height and depth of the current % leading; that is exactly what \strutbox is supposed to record. \vskip-\baselineskip % % \vadjust-items are inserted at the left edge of the type. So % the \llap here moves out into the left-hand margin. \llap{% % % For a thicker or thinner bar, change the `1pt'. \vrule height\baselineskip width1pt % % This is the space between the bar and the text. \hskip 12pt }% }% } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\undefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % For @cropmarks command. % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Output a mark which sets \thischapter, \thissection and \thiscolor. % We dump everything together because we only have one kind of mark. % This works because we only use \botmark / \topmark, not \firstmark. % % A mark contains a subexpression of the \ifcase ... \fi construct. % \get*marks macros below extract the needed part using \ifcase. % % Another complication is to let the user choose whether \thischapter % (\thissection) refers to the chapter (section) in effect at the top % of a page, or that at the bottom of a page. The solution is % described on page 260 of The TeXbook. It involves outputting two % marks for the sectioning macros, one before the section break, and % one after. I won't pretend I can describe this better than DEK... \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 \noexpand\or \the\toks4 \the\toks6 \noexpand\else \the\toks8 }% } % \topmark doesn't work for the very first chapter (after the title % page or the contents), so we use \firstmark there -- this gets us % the mark with the chapter defs, unless the user sneaks in, e.g., % @setcolor (or @url, or @link, etc.) between @contents and the very % first @chapter. \def\gettopheadingmarks{% \ifcase0\topmark\fi \ifx\thischapter\empty \ifcase0\firstmark\fi \fi } \def\getbottomheadingmarks{\ifcase1\botmark\fi} \def\getcolormarks{\ifcase2\topmark\fi} % Avoid "undefined control sequence" errors. \def\lastchapterdefs{} \def\lastsectiondefs{} \def\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. % We don't want .vr (or whatever) entries like this: % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\tt \backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingyyy.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 24pt \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1\relax \unvbox#1\relax \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\argtorun{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \argtorun. % (Similarily, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as enviroments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At runtime, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Evironment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty out of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} %% Simple single-character @ commands % @@ prints an @ % Kludge this until the fonts are right (grr). \def\@{{\tt\char64}} % This is turned off because it was never documented % and you can use @w{...} around a quote to suppress ligatures. %% Define @` and @' to be the same as ` and ' %% but suppressing ligatures. %\def\`{{`}} %\def\'{{'}} % Used to generate quoted braces. \def\mylbrace {{\tt\char123}} \def\myrbrace {{\tt\char125}} \let\{=\mylbrace \let\}=\myrbrace \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux/toc files. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \c \let\dotaccent = \. \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \t \let\ubaraccent = \b \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ptexi \else\ifx\temp\jmacro \j \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% \kern-.15em \TeX } % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% \fi\fi } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox \prevdepth = \dimen1 \checkinserts } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in % Old definition--didn't work. %\parseargdef\need{\par % %% This method tries to make TeX break the page naturally %% if the depth of the box does not fit. %{\baselineskip=0pt% %\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak %\prevdepth=-1000pt %}} \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @include file insert text of that file as input. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable \def\temp{\input #1 }% \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\next\centerH \else \let\next\centerV \fi \next{\hfil \ignorespaces#1\unskip \hfil}% } \def\centerH#1{% {% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }% } \def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} % @sp n outputs n lines of vertical space \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment \def\comment{\begingroup \catcode`\^^M=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent{% \restorefirstparagraphindent \indent }% \gdef\noindent{% \restorefirstparagraphindent \noindent }% \global\everypar = {% \kern -\parindent \restorefirstparagraphindent }% } \gdef\restorefirstparagraphindent{% \global \let \indent = \ptexindent \global \let \noindent = \ptexnoindent \global \everypar = {}% } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a \ character. % FYI, plain.tex uses \\ as a temporary control sequence (why?), but % this is not advertised and we don't care. Texinfo does not % otherwise define @\. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \tex \mathunderscore \let\\ = \mathbackslash \mathactive $\finishmath } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus } } % @bullet and @minus need the same treatment as @math, just above. \def\bullet{$\ptexbullet$} \def\minus{$-$} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in the cm % typewriter fonts as three actual period characters; on the other hand, % in other typewriter fonts three periods are wider than 1.5em. So do % whichever is larger. % \def\dots{% \leavevmode \setbox0=\hbox{...}% get width of three periods \ifdim\wd0 > 1.5em \dimen0 = \wd0 \else \dimen0 = 1.5em \fi \hbox to \dimen0{% \hskip 0pt plus.25fil .\hskip 0pt plus1fil .\hskip 0pt plus1fil .\hskip 0pt plus.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @comma{} is so commas can be inserted into text without messing up % Texinfo's parsing. % \let\comma = , % @refill is a no-op. \let\refill=\relax % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as \undefined, % borrowed from ifpdf.sty. \ifx\pdfoutput\undefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html % (and related messages, the final outcome is that it is up to the TeX % user to double the backslashes and otherwise make the string valid, so % that's what we do). % double active backslashes. % {\catcode`\@=0 \catcode`\\=\active @gdef@activebackslashdouble{% @catcode`@\=@active @let\=@doublebackslash} } % To handle parens, we must adopt a different approach, since parens are % not active characters. hyperref.dtx (which has the same problem as % us) handles it with this amazing macro to replace tokens, with minor % changes for Texinfo. It is included here under the GPL by permission % from the author, Heiko Oberdiek. % % #1 is the tokens to replace. % #2 is the replacement. % #3 is the control sequence with the string. % \def\HyPsdSubst#1#2#3{% \def\HyPsdReplace##1#1##2\END{% ##1% \ifx\\##2\\% \else #2% \HyReturnAfterFi{% \HyPsdReplace##2\END }% \fi }% \xdef#3{\expandafter\HyPsdReplace#3#1\END}% } \long\def\HyReturnAfterFi#1\fi{\fi#1} % #1 is a control sequence in which to do the replacements. \def\backslashparens#1{% \xdef#1{#1}% redefine it as its expansion; the definition is simply % \lastnode when called from \setref -> \pdfmkdest. \HyPsdSubst{(}{\realbackslash(}{#1}% \HyPsdSubst{)}{\realbackslash)}{#1}% } \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot be supported due to the design of the PDF format; use regular TeX (DVI output) for that.)} \ifpdf % % Color manipulation macros based on pdfcolor.tex. \def\cmykDarkRed{0.28 1 1 0.35} \def\cmykBlack{0 0 0 1} % \def\pdfsetcolor#1{\pdfliteral{#1 k}} % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\cmykBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % \pdfcatalog{/PageMode /UseOutlines} % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\dopdfimage#1#2#3{% \def\imagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\imageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % pdftex (and the PDF format) support .png, .jpg, .pdf (among % others). Let's try in that order. \let\pdfimgext=\empty \begingroup \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \openin 1 #1.pdf \ifeof 1 \errhelp = \nopdfimagehelp \errmessage{Could not find image file #1 for pdf}% \else \gdef\pdfimgext{pdf}% \fi \else \gdef\pdfimgext{JPG}% \fi \else \gdef\pdfimgext{jpeg}% \fi \else \gdef\pdfimgext{jpg}% \fi \else \gdef\pdfimgext{png}% \fi \closein 1 \endgroup % % without \immediate, pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifdim \wd0 >0pt width \imagewidth \fi \ifdim \wd2 >0pt height \imageheight \fi \ifnum\pdftexversion<13 #1.\pdfimgext \else {#1.\pdfimgext}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} % \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \turnoffactive \activebackslashdouble \makevalueexpandable \def\pdfdestname{#1}% \backslashparens\pdfdestname \safewhatsit{\pdfdest name{\pdfdestname} xyz}% }} % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % % by default, use a color that is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. \def\urlcolor{\cmykDarkRed} \def\linkcolor{\cmykDarkRed} \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \def\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}% \else % Doubled backslashes in the name. {\activebackslashdouble \xdef\pdfoutlinedest{#3}% \backslashparens\pdfoutlinedest}% \fi % % Also double the backslashes in the display string. {\activebackslashdouble \xdef\pdfoutlinetext{#1}% \backslashparens\pdfoutlinetext}% % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Thanh's hack / proper braces in bookmarks \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace % % Read toc silently, to get counts of subentries for \pdfoutline. \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % xx to do this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Right % now, I guess we'll just let the pdf reader have its way. \indexnofonts \setupdatafile \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \ifx\p\space\else\addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \fi \nextsp} \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable \leavevmode\setcolor{\urlcolor}% \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\setcolor = \gobble \let\pdfsetcolor = \gobble \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % Default leading. \newdimen\textleading \textleading = 13.2pt % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % % can get a sort of poor man's double spacing by redefining this. \def\baselinefactor{1} % \def\setleading#1{% \dimen0 = #1\relax \normalbaselineskip = \baselinefactor\dimen0 \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % PDF CMaps. See also LaTeX's t1.cmap. % % do nothing with this by default. \expandafter\let\csname cmapOT1\endcsname\gobble \expandafter\let\csname cmapOT1IT\endcsname\gobble \expandafter\let\csname cmapOT1TT\endcsname\gobble % if we are producing pdf, and we have \pdffontattr, then define cmaps. % (\pdffontattr was introduced many years ago, but people still run % older pdftex's; it's easy to conditionalize, so we do.) \ifpdf \ifx\pdffontattr\undefined \else \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1-0) %%Title: (TeX-OT1-0 TeX OT1 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1) /Supplement 0 >> def /CMapName /TeX-OT1-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <23> <26> <0023> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 40 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1IT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1IT-0) %%Title: (TeX-OT1IT-0 TeX OT1IT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1IT) /Supplement 0 >> def /CMapName /TeX-OT1IT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <25> <26> <0025> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 42 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <23> <0023> <24> <00A3> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1IT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1TT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1TT-0) %%Title: (TeX-OT1TT-0 TeX OT1TT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1TT) /Supplement 0 >> def /CMapName /TeX-OT1TT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 5 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <21> <26> <0021> <28> <5F> <0028> <61> <7E> <0061> endbfrange 32 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <2191> <0C> <2193> <0D> <0027> <0E> <00A1> <0F> <00BF> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <20> <2423> <27> <2019> <60> <2018> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1TT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi % Set the font macro #1 to the font named #2, adding on the % specified font prefix (normally `cm'). % #3 is the font's design size, #4 is a scale factor, #5 is the CMap % encoding (currently only OT1, OT1IT and OT1TT are allowed, pass % empty to omit). \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% } % This is what gets called when #5 of \setfont is empty. \let\cmap\gobble % emacs-page end of cmaps % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\undefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} %where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Definitions for a main text size of 11pt. This is the default in % Texinfo. % \def\definetextfontsizexi{% % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1095} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1}{OT1} \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\authorrm{\secrm} \def\authortt{\sectt} \def\titleecsize{2074} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2}{OT1} \setfont\chapit\itbshape{10}{\magstep3}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep3}{OT1} \setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} \setfont\chapsf\sfbshape{17}{1000}{OT1} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3}{OT1} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 \def\chapecsize{1728} % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1}{OT1} \setfont\secit\itbshape{10}{\magstep2}{OT1IT} \setfont\secsl\slbshape{10}{\magstep2}{OT1} \setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\secsf\sfbshape{12}{\magstep1}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2}{OT1} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 \def\sececsize{1440} % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} \setfont\ssecit\itbshape{10}{1315}{OT1IT} \setfont\ssecsl\slbshape{10}{1315}{OT1} \setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} \setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315}{OT1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} % Reduced fonts for @acro in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{1000}{OT1} \setfont\reducedit\itshape{10}{1000}{OT1IT} \setfont\reducedsl\slshape{10}{1000}{OT1} \setfont\reducedsf\sfshape{10}{1000}{OT1} \setfont\reducedsc\scshape{10}{1000}{OT1} \setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 \def\reducedecsize{1000} % reset the current fonts \textfonts \rm } % end of 11pt text font size definitions % Definitions to make the main text be 10pt Computer Modern, with % section, chapter, etc., sizes following suit. This is for the GNU % Press printing of the Emacs 22 manual. Maybe other manuals in the % future. Used with @smallbook, which sets the leading to 12pt. % \def\definetextfontsizex{% % Text fonts (10pt). \def\textnominalsize{10pt} \edef\mainmagstep{1000} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1000} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstephalf}{OT1} \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\authorrm{\secrm} \def\authortt{\sectt} \def\titleecsize{2074} % Chapter fonts (14.4pt). \def\chapnominalsize{14pt} \setfont\chaprm\rmbshape{12}{\magstep1}{OT1} \setfont\chapit\itbshape{10}{\magstep2}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep2}{OT1} \setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\chapsf\sfbshape{12}{\magstep1}{OT1} \let\chapbf\chaprm \setfont\chapsc\scbshape{10}{\magstep2}{OT1} \font\chapi=cmmi12 scaled \magstep1 \font\chapsy=cmsy10 scaled \magstep2 \def\chapecsize{1440} % Section fonts (12pt). \def\secnominalsize{12pt} \setfont\secrm\rmbshape{12}{1000}{OT1} \setfont\secit\itbshape{10}{\magstep1}{OT1IT} \setfont\secsl\slbshape{10}{\magstep1}{OT1} \setfont\sectt\ttbshape{12}{1000}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} \setfont\secsf\sfbshape{12}{1000}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep1}{OT1} \font\seci=cmmi12 \font\secsy=cmsy10 scaled \magstep1 \def\sececsize{1200} % Subsection fonts (10pt). \def\ssecnominalsize{10pt} \setfont\ssecrm\rmbshape{10}{1000}{OT1} \setfont\ssecit\itbshape{10}{1000}{OT1IT} \setfont\ssecsl\slbshape{10}{1000}{OT1} \setfont\ssectt\ttbshape{10}{1000}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} \setfont\ssecsf\sfbshape{10}{1000}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1000}{OT1} \font\sseci=cmmi10 \font\ssecsy=cmsy10 \def\ssececsize{1000} % Reduced fonts for @acro in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{900}{OT1} \setfont\reducedit\itshape{9}{1000}{OT1IT} \setfont\reducedsl\slshape{9}{1000}{OT1} \setfont\reducedsf\sfshape{9}{1000}{OT1} \setfont\reducedsc\scshape{10}{900}{OT1} \setfont\reducedttsl\ttslshape{10}{900}{OT1TT} \font\reducedi=cmmi9 \font\reducedsy=cmsy9 \def\reducedecsize{0900} % reduce space between paragraphs \divide\parskip by 2 % reset the current fonts \textfonts \rm } % end of 10pt text font size definitions % We provide the user-level command % @fonttextsize 10 % (or 11) to redefine the text font size. pt is assumed. % \def\xword{10} \def\xiword{11} % \parseargdef\fonttextsize{% \def\textsizearg{#1}% \wlog{doing @fonttextsize \textsizearg}% % % Set \globaldefs so that documents can use this inside @tex, since % makeinfo 4.8 does not support it, but we need it nonetheless. % \begingroup \globaldefs=1 \ifx\textsizearg\xword \definetextfontsizex \else \ifx\textsizearg\xiword \definetextfontsizexi \else \errhelp=\EMsimple \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} \fi\fi \endgroup } % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used in % the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl \def\curfontsize{text}% \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \def\titlefonts{% \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy \let\tenttsl=\titlettsl \def\curfontsize{title}% \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{25pt}} \def\titlefont#1{{\titlefonts\rm #1}} \def\chapfonts{% \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl \def\curfontsize{chap}% \def\lsize{sec}\def\lllsize{text}% \resetmathfonts \setleading{19pt}} \def\secfonts{% \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl \def\curfontsize{sec}% \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \def\curfontsize{ssec}% \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\curfontsize{reduced}% \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\curfontsize{small}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\curfontsize{smaller}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % % I wish the USA used A4 paper. % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \definetextfontsizexi % Define these so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000}{OT1} \setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000}{OT1} \setfont\shortconttt\ttshape{12}{1000}{OT1TT} %% Add scribe-like font environments, plus @l for inline lisp (usually sans %% serif) and @ii for TeX italic % \smartitalic{ARG} outputs arg in italics, followed by an italic correction % unless the following character is such as not to need one. \def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else \ptexslash\fi\fi\fi} \def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} \def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally uses \ttsl. % @var is set to this for defun arguments. \def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} % like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitalicx} \let\i=\smartitalic \let\slanted=\smartslanted \let\var=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic % @b, explicit bold. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\plainfrenchspacing{% \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } \def\samp#1{`\tclose{#1}'\null} \setfont\keyrm\rmshape{8}{1000}{OT1} \font\keysy=cmsy9 \def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% \vbox{\hrule\kern-0.4pt \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% \kern-0.4pt\hrule}% \kern-.06em\raise0.4pt\hbox{\angleright}}}} \def\key #1{{\nohyphenation \uppercase{#1}}\null} % The old definition, with no lozenge: %\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} \def\ctrl #1{{\tt \rawbackslash \hat}#1} % @file, @option are the same as @samp. \let\file=\samp \let\option=\samp % @code is a modification of @t, % which makes spaces the same size as normal in the surrounding text. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \plainfrenchspacing #1% }% \null } % We *must* turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. % -- rms. { \catcode`\-=\active \catcode`\_=\active \catcode`\'=\active \catcode`\`=\active % \global\def\code{\begingroup \catcode\rquoteChar=\active \catcode\lquoteChar=\active \let'\codequoteright \let`\codequoteleft % \catcode\dashChar=\active \catcode\underChar=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\realdash \let_\realunder \fi \codex } } \def\realdash{-} \def\codedash{-\discretionary{}{}{}} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } \def\codex #1{\tclose{#1}\endgroup} % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is undesirable in % some manuals, especially if they don't have long identifiers in % general. @allowcodebreaks provides a way to control this. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg'}% \fi\fi } % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle option `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct.' \kbdinputstyle distinct \def\xkey{\key} \def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\look}}\fi \else{\tclose{\kbdfont\look}}\fi} % For @indicateurl, @env, @command quotes seem unnecessary, so use \code. \let\indicateurl=\code \let\env=\code \let\command=\code % @uref (abbreviation for `urlref') takes an optional (comma-separated) % second argument specifying the text to display and an optional third % arg as text to display instead of (rather than in addition to) the url % itself. First (mandatory) arg is the url. Perhaps eventually put in % a hypertex \special here. % \def\uref#1{\douref #1,,,\finish} \def\douref#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} \def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi } % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % Hacks for glyphs from the EC fonts similar to \euro. We don't % use \let for the aliases, because sometimes we redefine the original % macro, and the alias should reflect the redefinition. \def\guillemetleft{{\ecfont \char"13}} \def\guillemotleft{\guillemetleft} \def\guillemetright{{\ecfont \char"14}} \def\guillemotright{\guillemetright} \def\guilsinglleft{{\ecfont \char"0E}} \def\guilsinglright{{\ecfont \char"0F}} \def\quotedblbase{{\ecfont \char"12}} \def\quotesinglbase{{\ecfont \char"0D}} % \def\ecfont{% % We can't distinguish serif/sanserif and italic/slanted, but this % is used for crude hacks anyway (like adding French and German % quotes to documents typeset with CM, where we lose kerning), so % hopefully nobody will notice/care. \edef\ecsize{\csname\curfontsize ecsize\endcsname}% \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize \fi \thisecfont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } % @textdegree - the normal degrees sign. % \def\textdegree{$^\circ$} % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\undefined \def\Orb{\mathhexbox20D} \fi % Quotes. \chardef\quotedblleft="5C \chardef\quotedblright=`\" \chardef\quoteleft=`\` \chardef\quoteright=`\' \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % Do an implicit @contents or @shortcontents after @end titlepage if the % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. % \newif\ifsetcontentsaftertitlepage \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue \newif\ifsetshortcontentsaftertitlepage \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue \parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % If they want short, they certainly want long too. \ifsetshortcontentsaftertitlepage \shortcontents \contents \global\let\shortcontents = \relax \global\let\contents = \relax \fi % \ifsetcontentsaftertitlepage \contents \global\let\contents = \relax \global\let\shortcontents = \relax \fi } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } %%% Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines \let\tt=\authortt} \parseargdef\title{% \checkenv\titlepage \leftline{\titlefonts\rm #1} % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\authorfont \leftline{#1}}% \fi } %%% Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\pageheight by -12pt \global\advance\vsize by -12pt } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @evenheadingmarks top \thischapter <- chapter at the top of a page % @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page % % The same set of arguments for: % % @oddheadingmarks % @evenfootingmarks % @oddfootingmarks % @everyheadingmarks % @everyfootingmarks \def\evenheadingmarks{\headingmarks{even}{heading}} \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} \def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } \def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname \global\expandafter\let\csname get#1#2marks\endcsname \temp } \everyheadingmarks bottom \everyfootingmarks bottom % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \def\headings #1 {\csname HEADINGS#1\endcsname} \def\HEADINGSoff{% \global\evenheadline={\hfil} \global\evenfootline={\hfil} \global\oddheadline={\hfil} \global\oddfootline={\hfil}} \HEADINGSoff % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\undefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi \def\itemcontents{#1}% % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% \vadjust{\penalty 1200}}% not good to break after first line of item. \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. % Assignments have to be global since we are inside the implicit group % of an alignment entry. Note that \everycr resets \everytab. \def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}% % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we encounter the problem it was intended to solve again. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi %% Test to see if parskip is larger than space between lines of %% table. If not, do nothing. %% If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller %% than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\- = \active \catcode`\_ = \active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\realdash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get special treatment of `@end ifset,' call \makeond and the redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \undefined % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname\donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % % Need these in case \tex is in effect and \{ is a \delimiter again. % But can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. \let\{ = \mylbrace \let\} = \myrbrace % % I don't entirely understand this, but when an index entry is % generated from a macro call, the \endinput which \scanmacro inserts % causes processing to be prematurely terminated. This is, % apparently, because \indexsorttmp is fully expanded, and \endinput % is an expandable command. The redefinition below makes \endinput % disappear altogether for that purpose -- although logging shows that % processing continues to some further point. On the other hand, it % seems \endinput does not hurt in the printed index arg, since that % is still getting written without apparent harm. % % Sample source (mac-idx3.tex, reported by Graham Percival to % help-texinfo, 22may06): % @macro funindex {WORD} % @findex xyz % @end macro % ... % @funindex commtest % % The above is not enough to reproduce the bug, but it gives the flavor. % % Sample whatsit resulting: % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} % % So: \let\endinput = \empty % % Do the redefinitions. \commondummies } % For the aux and toc files, @ is the escape character. So we want to % redefine everything using @ as the escape character (instead of % \realbackslash, still used for index files). When everything uses @, % this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % Do the redefinitions. \commondummies \otherbackslash } % Called from \indexdummies and \atdummies. % \def\commondummies{% % % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control% words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword ##1{\def##1{\string##1\space}}% \def\definedummyletter##1{\def##1{\string##1}}% \let\definedummyaccent\definedummyletter % \commondummiesnofonts % \definedummyletter\_% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\L \definedummyword\OE \definedummyword\O \definedummyword\aa \definedummyword\ae \definedummyword\l \definedummyword\oe \definedummyword\o \definedummyword\ss \definedummyword\exclamdown \definedummyword\questiondown \definedummyword\ordf \definedummyword\ordm % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\guillemetleft \definedummyword\guillemetright \definedummyword\guilsinglleft \definedummyword\guilsinglright \definedummyword\expansion \definedummyword\minus \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\quotedblbase \definedummyword\quotedblleft \definedummyword\quotedblright \definedummyword\quoteleft \definedummyword\quoteright \definedummyword\quotesinglbase \definedummyword\result \definedummyword\textdegree % % We want to disable all macros so that they are not expanded by \write. \macrolist % \normalturnoffactive % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % \def\commondummiesnofonts{% % Control letters and accents. \definedummyletter\!% \definedummyaccent\"% \definedummyaccent\'% \definedummyletter\*% \definedummyaccent\,% \definedummyletter\.% \definedummyletter\/% \definedummyletter\:% \definedummyaccent\=% \definedummyletter\?% \definedummyaccent\^% \definedummyaccent\`% \definedummyaccent\~% \definedummyword\u \definedummyword\v \definedummyword\H \definedummyword\dotaccent \definedummyword\ringaccent \definedummyword\tieaccent \definedummyword\ubaraccent \definedummyword\udotaccent \definedummyword\dotless % % Texinfo font commands. \definedummyword\b \definedummyword\i \definedummyword\r \definedummyword\sc \definedummyword\t % % Commands that take arguments. \definedummyword\acronym \definedummyword\cite \definedummyword\code \definedummyword\command \definedummyword\dfn \definedummyword\emph \definedummyword\env \definedummyword\file \definedummyword\kbd \definedummyword\key \definedummyword\math \definedummyword\option \definedummyword\pxref \definedummyword\ref \definedummyword\samp \definedummyword\strong \definedummyword\tie \definedummyword\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\definedummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\definedummyletter##1{\let##1\empty}% % Hopefully, all control words can become @asis. \let\definedummyword\definedummyaccent % \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% % how to handle braces? \def\_{\normalunderscore}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\aa{aa}% \def\ae{ae}% \def\l{l}% \def\oe{oe}% \def\o{o}% \def\ss{ss}% \def\exclamdown{!}% \def\questiondown{?}% \def\ordf{a}% \def\ordm{o}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\bullet{bullet}% \def\comma{,}% \def\copyright{copyright}% \def\registeredsymbol{R}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\euro{euro}% \def\guillemetleft{<<}% \def\guillemetright{>>}% \def\guilsinglleft{<}% \def\guilsinglright{>}% \def\expansion{==>}% \def\minus{-}% \def\pounds{pounds}% \def\point{.}% \def\print{-|}% \def\quotedblbase{"}% \def\quotedblleft{"}% \def\quotedblright{"}% \def\quoteleft{`}% \def\quoteright{'}% \def\quotesinglbase{,}% \def\result{=>}% \def\textdegree{degrees}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist } \let\indexbackslash=0 %overridden during \printindex. \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \safewhatsit\dosubindwrite }% \fi } % Write the entry in \toks0 to the index file: % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % Take care of unwanted page breaks/skips around a whatsit: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write or \pdfdest will make \lastskip zero. The result is that % sequences like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % \newskip\whatsitskip \newcount\whatsitpenalty % % ..., ready, GO: % \def\safewhatsit#1{% \ifhmode #1% \else % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \whatsitskip = \lastskip \edef\lastskipmacro{\the\lastskip}% \whatsitpenalty = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\whatsitskip glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\whatsitskip \fi % #1% % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\whatsitskip \fi \fi } % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \plainfrenchspacing \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 11 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \nobreak \vskip 0pt plus 3\baselineskip \penalty 0 \vskip 0pt plus -3\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus .5\baselineskip \leftline{\secbf #1}% % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip }} % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this frozes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \setbox\boxA = \hbox{#1}% \ifdim\wd\boxA = 0pt \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like plain.tex's \dotfill, except uses up at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% } % % All done with double columns. \def\enddoublecolumns{% % The following penalty ensures that the page builder is exercised % _before_ we change the output routine. This is necessary in the % following situation: % % The last section of the index consists only of a single entry. % Before this section, \pagetotal is less than \pagegoal, so no % break occurs before the last section starts. However, the last % section, consisting of \initial and the single \entry, does not % fit on the page and has to be broken off. Without the following % penalty the page builder will not be exercised until \eject % below, and by that time we'll already have changed the output % routine to the \balancecolumns version, so the next-to-last % double-column page will be processed with \balancecolumns, which % is wrong: The two columns will go to the main vertical list, with % the broken-off section in the recent contributions. As soon as % the output routine finishes, TeX starts reconsidering the page % break. The two columns and the broken-off section both fit on the % page, because the two columns now take up only half of the page % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns % and the final section into the vbox of \pageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the % page builder, unlike penalties (see The TeXbook, pp. 280-281). \penalty0 % \output = {% % Split the last of the double-column material. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % \unnumberedno is an oxymoron, of course. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines these (using marks) as the number+name, number % and name of the chapter. Page headings and footings can use % these. @section does likewise. \def\thischapter{} \def\thischapternum{} \def\thischaptername{} \def\thissection{} \def\thissectionnum{} \def\thissectionname{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achive this, remember the "biggest" unnum. sec. we are currently in: \chardef\unmlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unmlevel \chardef\unmlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unmlevel \def\headtype{U}% \else \chardef\unmlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % \message{\putwordChapter\space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % \def\appendixnum{\putwordAppendix\space \appendixletter}% \message{\appendixnum}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } \outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } \outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. \outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } \outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading % NOTE on use of \vbox for chapter headings, section headings, and such: % 1) We use \vbox rather than the earlier \line to permit % overlong headings to fold. % 2) \hyphenpenalty is set to 10000 because hyphenation in a % heading is obnoxious; this forbids it. % 3) Likewise, headings look best if no \parindent is used, and % if justification is not attempted. Hence \raggedright. \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\raggedright \rm #1\hfill}}% \bigskip \par\penalty 200\relax \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. %%% Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} %%% Define plain chapter starts, and page on/off switching for it % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip \def\chapbreak{\dobreak \chapheadingskip {-4000}} \def\chappager{\par\vfill\supereject} % Because \domark is called before \chapoddpage, the filler page will % get the headings for the next chapter, which is wrong. But we don't % care -- we just disable all headings on the filler page. \def\chapoddpage{% \chappager \ifodd\pageno \else \begingroup \evenheadline={\hfil}\evenfootline={\hfil}% \oddheadline={\hfil}\oddfootline={\hfil}% \hbox to 0pt{}% \chappager \endgroup \fi } \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% % Insert the first mark before the heading break (see notes for \domark). \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% \gdef\thissection{}}% % \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{\thischaptername}}% \else\ifx\temptype\Yomitfromtockeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{}}% \else\ifx\temptype\Yappendixkeyword \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\appendixletter}% \gdef\noexpand\thischapter{\putwordAppendix{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \else \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\the\chapno}% \gdef\noexpand\thischapter{\putwordChapter{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert the chapter heading break. \pchapsepmacro % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \domark % {% \chapfonts \rm % % Have to define \lastsection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\lastsection{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \nobreak % Avoid page breaks at the interline glue. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt\raggedright \rm #1\hfill}}\bigskip \par\nobreak } \def\chfopen #1#2{\chapoddpage {\chapfonts \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% \par\penalty 5000 % } \def\centerchfopen #1{% \chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 \parindent=0pt \hfill {\rm #1}\hfill}}\bigskip \par\nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% % Switch to the right set of fonts. \csname #2fonts\endcsname \rm % \def\sectionlevel{#2}% \def\temptype{#3}% % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs \ifx\temptype\Ynothingkeyword \ifx\sectionlevel\seckeyword \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% \gdef\thissection{\thissectionname}}% \fi \else\ifx\temptype\Yomitfromtockeyword % Don't redefine \thissection. \else\ifx\temptype\Yappendixkeyword \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% \gdef\noexpand\thissection{\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \else \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% \gdef\noexpand\thissection{\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert space above the heading. \csname #2headingbreak\endcsname % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevsectiondefs=\lastsectiondefs \domark % % Only insert the space after the number if we have a section number. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\lastsection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \lastsection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\lastsection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\lastsection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) \vskip-\parskip % % This is purely so the last item on the list is a known \penalty > % 10000. This is so \startdefun can avoid allowing breakpoints after % section headings. Otherwise, it would insert a valid breakpoint between: % % @section sec-whatever % @deffn def-whatever \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \tocreadfilename } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % redefined for the two-volume lispref. We always output on % \jobname.toc even if this is redefined. % \def\tocreadfilename{\jobname.toc} % Normal (long) toc. % \def\contents{% \startcontents{\putwordTOC}% \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, it should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\tentt \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \reducedsf error\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @tex ... @end tex escapes into raw Tex temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain tex @ character. \envdef\tex{% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \escapechar=`\\ % \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\*=\ptexstar \let\t=\ptext \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} \let\afterenvbreak = \aboveenvbreak % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing = t% \vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of \def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt \parindent = 0pt \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword % end paragraph for sake of leading, in case document has no blank % line. This is redundant with what happens in \aboveenvbreak, but % we need to do it before changing the fonts, and it's inconvenient % to change the fonts afterward. \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it by one command: \def\makedispenv #1#2{ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two synonyms: \def\maketwodispenvs #1#2#3{ \makedispenv{#1}{#3} \makedispenv{#2}{#3} } % @lisp: indented, narrowed, typewriter font; @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvs {lisp}{example}{% \nonfillstart \tt\quoteexpand \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenv {display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenv{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill \gobble } \let\Eflushright = \afterenvbreak % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \envdef\quotation{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \advance\rightskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\undefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % [Knuth] pp. 380,381,391 % Disable Spanish ligatures ?` and !` of \tt font \begingroup \catcode`\`=\active\gdef`{\relax\lq} \endgroup % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \catcode`\`=\active \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % \def\starttabbox{\setbox0=\hbox\bgroup} % Allow an option to not replace quotes with a regular directed right % quote/apostrophe (char 0x27), but instead use the undirected quote % from cmtt (char 0x0d). The undirected quote is ugly, so don't make it % the default, but it works for pasting with more pdf viewers (at least % evince), the lilypond developers report. xpdf does work with the % regular 0x27. % \def\codequoteright{% \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax '% \else \char'15 \fi \else \char'15 \fi } % % and a similar option for the left quote char vs. a grave accent. % Modern fonts display ASCII 0x60 as a grave accent, so some people like % the code environments to do likewise. % \def\codequoteleft{% \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax `% \else \char'22 \fi \else \char'22 \fi } % \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen0=\wd0 % the width so far, or since the previous tab \divide\dimen0 by\tabw \multiply\dimen0 by\tabw % compute previous multiple of \tabw \advance\dimen0 by\tabw % advance to next multiple of \tabw \wd0=\dimen0 \box0 \starttabbox }% } \catcode`\'=\active \gdef\rquoteexpand{\catcode\rquoteChar=\active \def'{\codequoteright}}% % \catcode`\`=\active \gdef\lquoteexpand{\catcode\lquoteChar=\active \def`{\codequoteleft}}% % \gdef\quoteexpand{\rquoteexpand \lquoteexpand}% \endgroup % start the verbatim environment. \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart % Easiest (and conventionally used) font for verbatim \tt \def\par{\leavevmode\egroup\box0\endgraf}% \catcode`\`=\active \tabexpand \quoteexpand % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is very desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt \newcount\defunpenalty % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \defunpenalty=10003 % Will keep this @deffn together with the % following @def command, see below. \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \printdefunline, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % % As a minor refinement, we avoid "club" headers by signalling % with penalty of 10003 after the very first @deffn in the % sequence (see above), and penalty of 10002 after any following % @def command. \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil \endgraf \nobreak\vskip -\parskip \penalty\defunpenalty % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remainnig is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } %%% Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } %%% Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } %%% Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } %%% Type: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % How we'll format the type name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % (plain.tex says that \dimen1 should be used only as global.) \parshape 2 0in \dimen0 \defargsindent \dimen2 % % Put the type name to the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% return value type \ifx\temp\empty\else \tclose{\temp} \fi #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. Let's try @var for that. \let\var=\ttslanted #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } % these should not use \errmessage; the glibc manual, at least, actually % has such constructs (when documenting function pointers). \def\badparencount{% \message{Warning: unbalanced parentheses in @def...}% \global\parencount=0 } \def\badbrackcount{% \message{Warning: unbalanced square brackets in @def...}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\undefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \def\scanmacro#1{% \begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % Undo catcode changes of \startcontents and \doprintindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. Previously, we had % \catcode`\\=\other instead. We'll see whether a problem appears % with macro expansion. --kasal, 19aug04 \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ % ... and \example \spaceisspace % % Append \endinput to make sure that TeX does not see the ending newline. % I've verified that it is necessary both for e-TeX and for ordinary TeX % --kasal, 29nov03 \scantokens{#1\endinput}% \endgroup } \def\scanexp#1{% \edef\temp{\noexpand\scanmacro{#1}}% \temp } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \definedummyword\macro1\definedummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\definedummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\endcsname \csname#2\endcsname } % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \. % Non-ASCII encodings make 8-bit characters active, so un-activate % them to avoid their expansion. Must do this non-globally, to % confine the change to the current group. % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. \def\scanctxt{% \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\@=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi } \def\scanargctxt{% \scanctxt \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% \scanctxt \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } \def\macroargctxt{% \scanctxt \catcode`\\=\other } % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0% \else \expandafter\parsemargdef \argl;% \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\definedummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\definedummyword \noexpand#1% \fi } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname #1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.blah for each blah % in the params list, to be ##N where N is the position in that list. % That gets used by \mbodybackslash (above). % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. \def\parsemargdef#1;{\paramno=0\def\paramlist{}% \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1% \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% % This defines the macro itself. There are six cases: recursive and % nonrecursive macros of zero, one, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % many \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \fi \fi} \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg) \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \expandafter\parsearg \fi \macnamexxx} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Just make them active and then expand them all to nothing. \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \lastsection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \atdummies % preserve commands, but don't expand them \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\lastsection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, during \shipout }% \fi } % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces \def\printedmanual{\ignorespaces #5}% \def\printedrefname{\ignorespaces #3}% \setbox1=\hbox{\printedmanual\unskip}% \setbox0=\hbox{\printedrefname\unskip}% \ifdim \wd0 = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax % Use the node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Use the actual chapter/section title appear inside % the square brackets. Use the real section title if we have it. \ifdim \wd1 > 0pt % It is in another manual, so we don't have it. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf \leavevmode \getfilename{#4}% {\indexnofonts \turnoffactive % See comments at \activebackslashdouble. {\activebackslashdouble \xdef\pdfxrefdest{#1}% \backslashparens\pdfxrefdest}% % \ifnum\filenamelength>0 \startlink attr{/Border [0 0 0]}% goto file{\the\filename.pdf} name{\pdfxrefdest}% \else \startlink attr{/Border [0 0 0]}% goto name{\pdfmkpgn{\pdfxrefdest}}% \fi }% \setcolor{\linkcolor}% \fi % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd0 = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % if the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd1 > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not % insert empty discretionaries after hyphens, which means that it will % not find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, this % is a loss. Therefore, we give the text of the node name again, so it % is as if TeX is seeing it for the first time. \ifdim \wd1 > 0pt \putwordSection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% \else % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via a macro so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% \fi \fi \endlink \endgroup} % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. % If its value is nonempty, SUFFIX is output afterward. % \def\refx#1#2{% {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs \message{\linenumber Undefined cross reference `#1'.}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% {% The node name might contain 8-bit characters, which in our current % implementation are changed to commands like @'e. Don't let these % mess up the control sequence name. \indexnofonts \turnoffactive \xdef\safexrefname{#1}% }% % \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 {\safexrefname}}% \fi } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {% \count1=128 \def\loop{% \catcode\count1=\other \advance\count1 by 1 \ifnum \count1<256 \loop \fi }% }% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\pagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut \futurelet\next\fo@t } }%end \catcode `\@=11 % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarily, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from ftp://tug.org/tex/epsf.tex.} % \def\image#1{% \ifx\epsfbox\undefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing this stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names % If the image is by itself, center it. \ifvmode \imagevmodetrue \nobreak\bigskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \line\bgroup \fi % % Output the image. \ifpdf \dopdfimage{#1}{#2}{#3}% \else % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \fi % \ifimagevmode \egroup \bigbreak \fi % space after the image \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \lastsection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\lastsection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \atdummies % % since we read the caption text in the macro world, where ^^M % is turned into a normal character, we have to scan it back, so % we don't write the literal three characters "^^M" into the aux file. \scanexp{% \xdef\noexpand\gtemp{% \ifx\thisshortcaption\empty \thiscaption \else \thisshortcaption \fi }% }% \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % % place the captured inserts % % BEWARE: when the floats start floating, we have to issue warning % whenever an insert appears inside a float which could possibly % float. --kasal, 26may04 % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \lastsection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % @documentlanguage is usually given very early, just after % @setfilename. If done too late, it may not override everything % properly. Single argument is the language (de) or locale (de_DE) % abbreviation. It would be nice if we could set up a hyphenation file. % { \catcode`\_ = \active \globaldefs=1 \parseargdef\documentlanguage{\begingroup \let_=\normalunderscore % normal _ character for filenames \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \openin 1 txi-#1.tex \ifeof 1 \documentlanguagetrywithoutunderscore{#1_\finish}% \else \input txi-#1.tex \fi \closein 1 \endgroup \endgroup} } % % If they passed de_DE, and txi-de_DE.tex doesn't exist, % try txi-de.tex. % \def\documentlanguagetrywithoutunderscore#1_#2\finish{% \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \input txi-#1.tex \fi \closein 1 } % \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? In the current directory should work if nowhere else does.} % Set the catcode of characters 128 through 255 to the specified number. % \def\setnonasciicharscatcode#1{% \count255=128 \loop\ifnum\count255<256 \global\catcode\count255=#1\relax \advance\count255 by 1 \repeat } \def\setnonasciicharscatcodenonglobal#1{% \count255=128 \loop\ifnum\count255<256 \catcode\count255=#1\relax \advance\count255 by 1 \repeat } % @documentencoding sets the definition of non-ASCII characters % according to the specified encoding. % \parseargdef\documentencoding{% % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% % % Supported encodings: names converted to tokens in order to be able % to compare them with \ifx. \def\ascii{\csname US-ASCII.enc\endcsname}% \def\latnine{\csname ISO-8859-15.enc\endcsname}% \def\latone{\csname ISO-8859-1.enc\endcsname}% \def\lattwo{\csname ISO-8859-2.enc\endcsname}% \def\utfeight{\csname UTF-8.enc\endcsname}% % \ifx \declaredencoding \ascii \asciichardefs % \else \ifx \declaredencoding \lattwo \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight \setnonasciicharscatcode\active \utfeightchardefs % \else \message{Unknown document encoding #1, ignoring.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii } % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} % First, make active non-ASCII characters in order for them to be % correctly categorized when TeX reads the replacement text of % macros containing the character definitions. \setnonasciicharscatcode\active % % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% \gdef^^a0{~} \gdef^^a1{\exclamdown} \gdef^^a2{\missingcharmsg{CENT SIGN}} \gdef^^a3{{\pounds}} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\missingcharmsg{YEN SIGN}} \gdef^^a6{\missingcharmsg{BROKEN BAR}} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\copyright} \gdef^^aa{\ordf} \gdef^^ab{\missingcharmsg{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}} \gdef^^ac{$\lnot$} \gdef^^ad{\-} \gdef^^ae{\registeredsymbol} \gdef^^af{\={}} % \gdef^^b0{\textdegree} \gdef^^b1{$\pm$} \gdef^^b2{$^2$} \gdef^^b3{$^3$} \gdef^^b4{\'{}} \gdef^^b5{$\mu$} \gdef^^b6{\P} % \gdef^^b7{$^.$} \gdef^^b8{\cedilla\ } \gdef^^b9{$^1$} \gdef^^ba{\ordm} % \gdef^^bb{\missingcharmsg{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}} \gdef^^bc{$1\over4$} \gdef^^bd{$1\over2$} \gdef^^be{$3\over4$} \gdef^^bf{\questiondown} % \gdef^^c0{\`A} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\~A} \gdef^^c4{\"A} \gdef^^c5{\ringaccent A} \gdef^^c6{\AE} \gdef^^c7{\cedilla C} \gdef^^c8{\`E} \gdef^^c9{\'E} \gdef^^ca{\^E} \gdef^^cb{\"E} \gdef^^cc{\`I} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\"I} % \gdef^^d0{\missingcharmsg{LATIN CAPITAL LETTER ETH}} \gdef^^d1{\~N} \gdef^^d2{\`O} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\~O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\O} \gdef^^d9{\`U} \gdef^^da{\'U} \gdef^^db{\^U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\missingcharmsg{LATIN CAPITAL LETTER THORN}} \gdef^^df{\ss} % \gdef^^e0{\`a} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\~a} \gdef^^e4{\"a} \gdef^^e5{\ringaccent a} \gdef^^e6{\ae} \gdef^^e7{\cedilla c} \gdef^^e8{\`e} \gdef^^e9{\'e} \gdef^^ea{\^e} \gdef^^eb{\"e} \gdef^^ec{\`{\dotless i}} \gdef^^ed{\'{\dotless i}} \gdef^^ee{\^{\dotless i}} \gdef^^ef{\"{\dotless i}} % \gdef^^f0{\missingcharmsg{LATIN SMALL LETTER ETH}} \gdef^^f1{\~n} \gdef^^f2{\`o} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\~o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\o} \gdef^^f9{\`u} \gdef^^fa{\'u} \gdef^^fb{\^u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\missingcharmsg{LATIN SMALL LETTER THORN}} \gdef^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. \def\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % \gdef^^a4{\euro} \gdef^^a6{\v S} \gdef^^a8{\v s} \gdef^^b4{\v Z} \gdef^^b8{\v z} \gdef^^bc{\OE} \gdef^^bd{\oe} \gdef^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% \gdef^^a0{~} \gdef^^a1{\missingcharmsg{LATIN CAPITAL LETTER A WITH OGONEK}} \gdef^^a2{\u{}} \gdef^^a3{\L} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\v L} \gdef^^a6{\'S} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\v S} \gdef^^aa{\cedilla S} \gdef^^ab{\v T} \gdef^^ac{\'Z} \gdef^^ad{\-} \gdef^^ae{\v Z} \gdef^^af{\dotaccent Z} % \gdef^^b0{\textdegree} \gdef^^b1{\missingcharmsg{LATIN SMALL LETTER A WITH OGONEK}} \gdef^^b2{\missingcharmsg{OGONEK}} \gdef^^b3{\l} \gdef^^b4{\'{}} \gdef^^b5{\v l} \gdef^^b6{\'s} \gdef^^b7{\v{}} \gdef^^b8{\cedilla\ } \gdef^^b9{\v s} \gdef^^ba{\cedilla s} \gdef^^bb{\v t} \gdef^^bc{\'z} \gdef^^bd{\H{}} \gdef^^be{\v z} \gdef^^bf{\dotaccent z} % \gdef^^c0{\'R} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\u A} \gdef^^c4{\"A} \gdef^^c5{\'L} \gdef^^c6{\'C} \gdef^^c7{\cedilla C} \gdef^^c8{\v C} \gdef^^c9{\'E} \gdef^^ca{\missingcharmsg{LATIN CAPITAL LETTER E WITH OGONEK}} \gdef^^cb{\"E} \gdef^^cc{\v E} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\v D} % \gdef^^d0{\missingcharmsg{LATIN CAPITAL LETTER D WITH STROKE}} \gdef^^d1{\'N} \gdef^^d2{\v N} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\H O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\v R} \gdef^^d9{\ringaccent U} \gdef^^da{\'U} \gdef^^db{\H U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\cedilla T} \gdef^^df{\ss} % \gdef^^e0{\'r} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\u a} \gdef^^e4{\"a} \gdef^^e5{\'l} \gdef^^e6{\'c} \gdef^^e7{\cedilla c} \gdef^^e8{\v c} \gdef^^e9{\'e} \gdef^^ea{\missingcharmsg{LATIN SMALL LETTER E WITH OGONEK}} \gdef^^eb{\"e} \gdef^^ec{\v e} \gdef^^ed{\'\i} \gdef^^ee{\^\i} \gdef^^ef{\v d} % \gdef^^f0{\missingcharmsg{LATIN SMALL LETTER D WITH STROKE}} \gdef^^f1{\'n} \gdef^^f2{\v n} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\H o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\v r} \gdef^^f9{\ringaccent u} \gdef^^fa{\'u} \gdef^^fb{\H u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\cedilla t} \gdef^^ff{\dotaccent{}} } % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some % changes for Texinfo conventions. It is included here under the GPL by % permission from Frank Mittelbach and the LaTeX team. % \newcount\countUTFx \newcount\countUTFy \newcount\countUTFz \gdef\UTFviiiTwoOctets#1#2{\expandafter \UTFviiiDefined\csname u8:#1\string #2\endcsname} % \gdef\UTFviiiThreeOctets#1#2#3{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} % \gdef\UTFviiiFourOctets#1#2#3#4{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} \gdef\UTFviiiDefined#1{% \ifx #1\relax \message{\linenumber Unicode char \string #1 not defined for Texinfo}% \else \expandafter #1% \fi } \begingroup \catcode`\~13 \catcode`\"12 \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiTwoOctets\string~}} \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiThreeOctets\string~}} \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiFourOctets\string~}} \UTFviiiLoop \endgroup \begingroup \catcode`\"=12 \catcode`\<=12 \catcode`\.=12 \catcode`\,=12 \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 \gdef\DeclareUnicodeCharacter#1#2{% \countUTFz = "#1\relax \wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% \begingroup \parseXMLCharref \def\UTFviiiTwoOctets##1##2{% \csname u8:##1\string ##2\endcsname}% \def\UTFviiiThreeOctets##1##2##3{% \csname u8:##1\string ##2\string ##3\endcsname}% \def\UTFviiiFourOctets##1##2##3##4{% \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter \gdef\UTFviiiTmp{#2}% \endgroup} \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% \parseUTFviiiB C\UTFviiiTwoOctets.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% \fi\fi\fi } \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 \countUTFy = \countUTFz \multiply\countUTFz by 64 \advance\countUTFx by -\countUTFz \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup \def\utfeightchardefs{% \DeclareUnicodeCharacter{00A0}{\tie} \DeclareUnicodeCharacter{00A1}{\exclamdown} \DeclareUnicodeCharacter{00A3}{\pounds} \DeclareUnicodeCharacter{00A8}{\"{ }} \DeclareUnicodeCharacter{00A9}{\copyright} \DeclareUnicodeCharacter{00AA}{\ordf} \DeclareUnicodeCharacter{00AB}{\guillemetleft} \DeclareUnicodeCharacter{00AD}{\-} \DeclareUnicodeCharacter{00AE}{\registeredsymbol} \DeclareUnicodeCharacter{00AF}{\={ }} \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} \DeclareUnicodeCharacter{00B4}{\'{ }} \DeclareUnicodeCharacter{00B8}{\cedilla{ }} \DeclareUnicodeCharacter{00BA}{\ordm} \DeclareUnicodeCharacter{00BB}{\guillemetright} \DeclareUnicodeCharacter{00BF}{\questiondown} \DeclareUnicodeCharacter{00C0}{\`A} \DeclareUnicodeCharacter{00C1}{\'A} \DeclareUnicodeCharacter{00C2}{\^A} \DeclareUnicodeCharacter{00C3}{\~A} \DeclareUnicodeCharacter{00C4}{\"A} \DeclareUnicodeCharacter{00C5}{\AA} \DeclareUnicodeCharacter{00C6}{\AE} \DeclareUnicodeCharacter{00C7}{\cedilla{C}} \DeclareUnicodeCharacter{00C8}{\`E} \DeclareUnicodeCharacter{00C9}{\'E} \DeclareUnicodeCharacter{00CA}{\^E} \DeclareUnicodeCharacter{00CB}{\"E} \DeclareUnicodeCharacter{00CC}{\`I} \DeclareUnicodeCharacter{00CD}{\'I} \DeclareUnicodeCharacter{00CE}{\^I} \DeclareUnicodeCharacter{00CF}{\"I} \DeclareUnicodeCharacter{00D1}{\~N} \DeclareUnicodeCharacter{00D2}{\`O} \DeclareUnicodeCharacter{00D3}{\'O} \DeclareUnicodeCharacter{00D4}{\^O} \DeclareUnicodeCharacter{00D5}{\~O} \DeclareUnicodeCharacter{00D6}{\"O} \DeclareUnicodeCharacter{00D8}{\O} \DeclareUnicodeCharacter{00D9}{\`U} \DeclareUnicodeCharacter{00DA}{\'U} \DeclareUnicodeCharacter{00DB}{\^U} \DeclareUnicodeCharacter{00DC}{\"U} \DeclareUnicodeCharacter{00DD}{\'Y} \DeclareUnicodeCharacter{00DF}{\ss} \DeclareUnicodeCharacter{00E0}{\`a} \DeclareUnicodeCharacter{00E1}{\'a} \DeclareUnicodeCharacter{00E2}{\^a} \DeclareUnicodeCharacter{00E3}{\~a} \DeclareUnicodeCharacter{00E4}{\"a} \DeclareUnicodeCharacter{00E5}{\aa} \DeclareUnicodeCharacter{00E6}{\ae} \DeclareUnicodeCharacter{00E7}{\cedilla{c}} \DeclareUnicodeCharacter{00E8}{\`e} \DeclareUnicodeCharacter{00E9}{\'e} \DeclareUnicodeCharacter{00EA}{\^e} \DeclareUnicodeCharacter{00EB}{\"e} \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} \DeclareUnicodeCharacter{00F1}{\~n} \DeclareUnicodeCharacter{00F2}{\`o} \DeclareUnicodeCharacter{00F3}{\'o} \DeclareUnicodeCharacter{00F4}{\^o} \DeclareUnicodeCharacter{00F5}{\~o} \DeclareUnicodeCharacter{00F6}{\"o} \DeclareUnicodeCharacter{00F8}{\o} \DeclareUnicodeCharacter{00F9}{\`u} \DeclareUnicodeCharacter{00FA}{\'u} \DeclareUnicodeCharacter{00FB}{\^u} \DeclareUnicodeCharacter{00FC}{\"u} \DeclareUnicodeCharacter{00FD}{\'y} \DeclareUnicodeCharacter{00FF}{\"y} \DeclareUnicodeCharacter{0100}{\=A} \DeclareUnicodeCharacter{0101}{\=a} \DeclareUnicodeCharacter{0102}{\u{A}} \DeclareUnicodeCharacter{0103}{\u{a}} \DeclareUnicodeCharacter{0106}{\'C} \DeclareUnicodeCharacter{0107}{\'c} \DeclareUnicodeCharacter{0108}{\^C} \DeclareUnicodeCharacter{0109}{\^c} \DeclareUnicodeCharacter{010A}{\dotaccent{C}} \DeclareUnicodeCharacter{010B}{\dotaccent{c}} \DeclareUnicodeCharacter{010C}{\v{C}} \DeclareUnicodeCharacter{010D}{\v{c}} \DeclareUnicodeCharacter{010E}{\v{D}} \DeclareUnicodeCharacter{0112}{\=E} \DeclareUnicodeCharacter{0113}{\=e} \DeclareUnicodeCharacter{0114}{\u{E}} \DeclareUnicodeCharacter{0115}{\u{e}} \DeclareUnicodeCharacter{0116}{\dotaccent{E}} \DeclareUnicodeCharacter{0117}{\dotaccent{e}} \DeclareUnicodeCharacter{011A}{\v{E}} \DeclareUnicodeCharacter{011B}{\v{e}} \DeclareUnicodeCharacter{011C}{\^G} \DeclareUnicodeCharacter{011D}{\^g} \DeclareUnicodeCharacter{011E}{\u{G}} \DeclareUnicodeCharacter{011F}{\u{g}} \DeclareUnicodeCharacter{0120}{\dotaccent{G}} \DeclareUnicodeCharacter{0121}{\dotaccent{g}} \DeclareUnicodeCharacter{0124}{\^H} \DeclareUnicodeCharacter{0125}{\^h} \DeclareUnicodeCharacter{0128}{\~I} \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} \DeclareUnicodeCharacter{012A}{\=I} \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} \DeclareUnicodeCharacter{012C}{\u{I}} \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} \DeclareUnicodeCharacter{0130}{\dotaccent{I}} \DeclareUnicodeCharacter{0131}{\dotless{i}} \DeclareUnicodeCharacter{0132}{IJ} \DeclareUnicodeCharacter{0133}{ij} \DeclareUnicodeCharacter{0134}{\^J} \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} \DeclareUnicodeCharacter{0139}{\'L} \DeclareUnicodeCharacter{013A}{\'l} \DeclareUnicodeCharacter{0141}{\L} \DeclareUnicodeCharacter{0142}{\l} \DeclareUnicodeCharacter{0143}{\'N} \DeclareUnicodeCharacter{0144}{\'n} \DeclareUnicodeCharacter{0147}{\v{N}} \DeclareUnicodeCharacter{0148}{\v{n}} \DeclareUnicodeCharacter{014C}{\=O} \DeclareUnicodeCharacter{014D}{\=o} \DeclareUnicodeCharacter{014E}{\u{O}} \DeclareUnicodeCharacter{014F}{\u{o}} \DeclareUnicodeCharacter{0150}{\H{O}} \DeclareUnicodeCharacter{0151}{\H{o}} \DeclareUnicodeCharacter{0152}{\OE} \DeclareUnicodeCharacter{0153}{\oe} \DeclareUnicodeCharacter{0154}{\'R} \DeclareUnicodeCharacter{0155}{\'r} \DeclareUnicodeCharacter{0158}{\v{R}} \DeclareUnicodeCharacter{0159}{\v{r}} \DeclareUnicodeCharacter{015A}{\'S} \DeclareUnicodeCharacter{015B}{\'s} \DeclareUnicodeCharacter{015C}{\^S} \DeclareUnicodeCharacter{015D}{\^s} \DeclareUnicodeCharacter{015E}{\cedilla{S}} \DeclareUnicodeCharacter{015F}{\cedilla{s}} \DeclareUnicodeCharacter{0160}{\v{S}} \DeclareUnicodeCharacter{0161}{\v{s}} \DeclareUnicodeCharacter{0162}{\cedilla{t}} \DeclareUnicodeCharacter{0163}{\cedilla{T}} \DeclareUnicodeCharacter{0164}{\v{T}} \DeclareUnicodeCharacter{0168}{\~U} \DeclareUnicodeCharacter{0169}{\~u} \DeclareUnicodeCharacter{016A}{\=U} \DeclareUnicodeCharacter{016B}{\=u} \DeclareUnicodeCharacter{016C}{\u{U}} \DeclareUnicodeCharacter{016D}{\u{u}} \DeclareUnicodeCharacter{016E}{\ringaccent{U}} \DeclareUnicodeCharacter{016F}{\ringaccent{u}} \DeclareUnicodeCharacter{0170}{\H{U}} \DeclareUnicodeCharacter{0171}{\H{u}} \DeclareUnicodeCharacter{0174}{\^W} \DeclareUnicodeCharacter{0175}{\^w} \DeclareUnicodeCharacter{0176}{\^Y} \DeclareUnicodeCharacter{0177}{\^y} \DeclareUnicodeCharacter{0178}{\"Y} \DeclareUnicodeCharacter{0179}{\'Z} \DeclareUnicodeCharacter{017A}{\'z} \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} \DeclareUnicodeCharacter{017C}{\dotaccent{z}} \DeclareUnicodeCharacter{017D}{\v{Z}} \DeclareUnicodeCharacter{017E}{\v{z}} \DeclareUnicodeCharacter{01C4}{D\v{Z}} \DeclareUnicodeCharacter{01C5}{D\v{z}} \DeclareUnicodeCharacter{01C6}{d\v{z}} \DeclareUnicodeCharacter{01C7}{LJ} \DeclareUnicodeCharacter{01C8}{Lj} \DeclareUnicodeCharacter{01C9}{lj} \DeclareUnicodeCharacter{01CA}{NJ} \DeclareUnicodeCharacter{01CB}{Nj} \DeclareUnicodeCharacter{01CC}{nj} \DeclareUnicodeCharacter{01CD}{\v{A}} \DeclareUnicodeCharacter{01CE}{\v{a}} \DeclareUnicodeCharacter{01CF}{\v{I}} \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} \DeclareUnicodeCharacter{01D1}{\v{O}} \DeclareUnicodeCharacter{01D2}{\v{o}} \DeclareUnicodeCharacter{01D3}{\v{U}} \DeclareUnicodeCharacter{01D4}{\v{u}} \DeclareUnicodeCharacter{01E2}{\={\AE}} \DeclareUnicodeCharacter{01E3}{\={\ae}} \DeclareUnicodeCharacter{01E6}{\v{G}} \DeclareUnicodeCharacter{01E7}{\v{g}} \DeclareUnicodeCharacter{01E8}{\v{K}} \DeclareUnicodeCharacter{01E9}{\v{k}} \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} \DeclareUnicodeCharacter{01F1}{DZ} \DeclareUnicodeCharacter{01F2}{Dz} \DeclareUnicodeCharacter{01F3}{dz} \DeclareUnicodeCharacter{01F4}{\'G} \DeclareUnicodeCharacter{01F5}{\'g} \DeclareUnicodeCharacter{01F8}{\`N} \DeclareUnicodeCharacter{01F9}{\`n} \DeclareUnicodeCharacter{01FC}{\'{\AE}} \DeclareUnicodeCharacter{01FD}{\'{\ae}} \DeclareUnicodeCharacter{01FE}{\'{\O}} \DeclareUnicodeCharacter{01FF}{\'{\o}} \DeclareUnicodeCharacter{021E}{\v{H}} \DeclareUnicodeCharacter{021F}{\v{h}} \DeclareUnicodeCharacter{0226}{\dotaccent{A}} \DeclareUnicodeCharacter{0227}{\dotaccent{a}} \DeclareUnicodeCharacter{0228}{\cedilla{E}} \DeclareUnicodeCharacter{0229}{\cedilla{e}} \DeclareUnicodeCharacter{022E}{\dotaccent{O}} \DeclareUnicodeCharacter{022F}{\dotaccent{o}} \DeclareUnicodeCharacter{0232}{\=Y} \DeclareUnicodeCharacter{0233}{\=y} \DeclareUnicodeCharacter{0237}{\dotless{j}} \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} \DeclareUnicodeCharacter{1E20}{\=G} \DeclareUnicodeCharacter{1E21}{\=g} \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} \DeclareUnicodeCharacter{1E26}{\"H} \DeclareUnicodeCharacter{1E27}{\"h} \DeclareUnicodeCharacter{1E30}{\'K} \DeclareUnicodeCharacter{1E31}{\'k} \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} \DeclareUnicodeCharacter{1E3E}{\'M} \DeclareUnicodeCharacter{1E3F}{\'m} \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} \DeclareUnicodeCharacter{1E54}{\'P} \DeclareUnicodeCharacter{1E55}{\'p} \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} \DeclareUnicodeCharacter{1E7C}{\~V} \DeclareUnicodeCharacter{1E7D}{\~v} \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} \DeclareUnicodeCharacter{1E80}{\`W} \DeclareUnicodeCharacter{1E81}{\`w} \DeclareUnicodeCharacter{1E82}{\'W} \DeclareUnicodeCharacter{1E83}{\'w} \DeclareUnicodeCharacter{1E84}{\"W} \DeclareUnicodeCharacter{1E85}{\"w} \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} \DeclareUnicodeCharacter{1E8C}{\"X} \DeclareUnicodeCharacter{1E8D}{\"x} \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} \DeclareUnicodeCharacter{1E90}{\^Z} \DeclareUnicodeCharacter{1E91}{\^z} \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} \DeclareUnicodeCharacter{1E97}{\"t} \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} \DeclareUnicodeCharacter{1EBC}{\~E} \DeclareUnicodeCharacter{1EBD}{\~e} \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} \DeclareUnicodeCharacter{1EF2}{\`Y} \DeclareUnicodeCharacter{1EF3}{\`y} \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} \DeclareUnicodeCharacter{1EF8}{\~Y} \DeclareUnicodeCharacter{1EF9}{\~y} \DeclareUnicodeCharacter{2013}{--} \DeclareUnicodeCharacter{2014}{---} \DeclareUnicodeCharacter{2018}{\quoteleft} \DeclareUnicodeCharacter{2019}{\quoteright} \DeclareUnicodeCharacter{201A}{\quotesinglbase} \DeclareUnicodeCharacter{201C}{\quotedblleft} \DeclareUnicodeCharacter{201D}{\quotedblright} \DeclareUnicodeCharacter{201E}{\quotedblbase} \DeclareUnicodeCharacter{2022}{\bullet} \DeclareUnicodeCharacter{2026}{\dots} \DeclareUnicodeCharacter{2039}{\guilsinglleft} \DeclareUnicodeCharacter{203A}{\guilsinglright} \DeclareUnicodeCharacter{20AC}{\euro} \DeclareUnicodeCharacter{2192}{\expansion} \DeclareUnicodeCharacter{21D2}{\result} \DeclareUnicodeCharacter{2212}{\minus} \DeclareUnicodeCharacter{2217}{\point} \DeclareUnicodeCharacter{2261}{\equiv} }% end of \utfeightchardefs % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % Make non-ASCII characters printable again for compatibility with % existing Texinfo documents that may use them, even without declaring a % document encoding. % \setnonasciicharscatcode \other \message{formatting,} \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be so finicky about underfull hboxes, either. \hbadness = 2000 % Following George Bush, get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \pageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \pagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax % if we don't reset these, they will remain at "1 true in" of % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{607.2pt}{6in}% that's 46 lines {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {-.2in}{0in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{673.2pt}{160mm}% that's 51 lines {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1\relax \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \catcode`\~=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\+=\other \catcode`\$=\other \def\normaldoublequote{"} \def\normaltilde{~} \def\normalcaret{^} \def\normalunderscore{_} \def\normalverticalbar{|} \def\normalless{<} \def\normalgreater{>} \def\normalplus{+} \def\normaldollar{$}%$ font-lock fix % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \let\realunder=_ % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active @def@normalbackslash{{@tt@backslashcurfont}} % On startup, @fixbackslash assigns: % @let \ = @normalbackslash % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. % @def@normalturnoffactive{% @let\=@normalbackslash @let"=@normaldoublequote @let~=@normaltilde @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let<=@normalless @let>=@normalgreater @let+=@normalplus @let$=@normaldollar %$ font-lock fix @unsepspaces } % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\' in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These look ok in all fonts, so just make them not special. @catcode`@& = @other @catcode`@# = @other @catcode`@% = @other @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore emacs-jabber-0.8.0/jabber.texi0000644000175100017510000032527511252704557013123 00000000000000\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename jabber.info @settitle jabber.el manual 0.8 @c %**end of header @dircategory Emacs @direntry * jabber.el: (jabber). Emacs Jabber client @end direntry @copying This manual is for jabber.el, version 0.8. Copyright @copyright{} 2004, 2005, 2006, 2007, 2008 Magnus Henoch, Tom Berger. @quotation Permission is granted to make and distribute verbatim copies or modified versions of this manual, provided the copyright notice and this permission notice are preserved on all copies. @end quotation @end copying @titlepage @title jabber.el @subtitle instant messaging for Jabber @author by Magnus Henoch and Tom Berger @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @ifnottex @node Top, Introduction, (dir), (dir) @top jabber.el manual @insertcopying @end ifnottex @menu * Introduction:: * Basic operation:: * Groupchat:: * Composing messages:: * File transfer:: * Services:: * Personal information:: * Avatars:: * Time queries:: * Useful features:: * Message history:: * Typing notifications:: * Roster import and export:: * XMPP URIs:: * Customization:: * Hacking and extending:: * Protocol support:: * Concept index:: * Function index:: * Variable index:: @end menu @node Introduction, Basic operation, Top, Top @chapter Introduction jabber.el is a Jabber client running under Emacs. For more information on the open-protocol instant messaging network Jabber, please visit @uref{http://www.jabber.org}. As a Jabber client, jabber.el is mostly just a face in the crowd, except that it uses buffers where GUI clients have windows. There is a roster buffer, and to chat with someone you open a chat buffer, and there are buffers for interaction with servers and services. Then again, jabber.el delivers excellent console performance and customizable hooks (if you have speech synthesizer software, hook it up to your presence alerts). jabber.el does not yet support PGP encryption, sending and receiving roster items, and various other things. @menu * Contact:: @end menu @node Contact, , Introduction, Introduction @section Contact @itemize @bullet @item There is a web page at @uref{http://emacs-jabber.sf.net/}. @item There is a Sourceforge project page at @uref{http://sourceforge.net/projects/emacs-jabber}, with bug and patch trackers. @item There is a mailing list: @email{emacs-jabber-general@@lists.sourceforge.net}, @uref{https://lists.sourceforge.net/lists/listinfo/emacs-jabber-general}, @uref{http://dir.gmane.org/gmane.emacs.jabber.general} @item There is a chat room, @code{jabber.el@@conference.jabber.se}. If you have successfully connected, you can join it by typing @kbd{M-x jabber-groupchat-join} and entering the address. @end itemize @node Basic operation, Groupchat, Introduction, Top @chapter Basic operation This chapter is intended as an introduction to basic usage of jabber.el. If you have used Jabber before and are familiar with the terminology, you might find it a bit too basic---in that case, just skim it, making sure to pick up the commands mentioned. I'll assume that you have already successfully installed jabber.el; if not, consult the @file{README} file. Also, make sure you have @code{(require 'jabber)} or @code{(load "jabber-autoloads")} in your @file{.emacs}. There are a handful of global keybindings for common commands. They start with @kbd{C-x C-j}, and you can get a list of them by typing @kbd{C-x C-j C-h}. @menu * Do you have a Jabber account?:: * Registering an account:: * Connecting:: * Chatting:: * Presence:: * Presence subscription:: * Roster buffer:: @end menu @node Do you have a Jabber account?, Registering an account, Basic operation, Basic operation @section Do you have a Jabber account? Jabber has become rather popular as an instant messaging technology. Several sites use it, but often not under the names ``Jabber'' or ``XMPP''. Examples: @itemize @bullet @item Google Talk uses Jabber. If you have a Gmail address, you can use it as a Jabber ID. @xref{Account settings}, for Google-specific configuration. @item LJ Talk (of Livejournal) uses Jabber. Your Jabber ID is @samp{@var{ljusername}@@livejournal.com}. @end itemize @node Registering an account, Connecting, Do you have a Jabber account?, Basic operation @section Registering an account @cindex Registering an account If you do not yet have a Jabber account, you can register one. The registration processes for various servers differ, but many servers support so-called ``in-band registration'', which is described in this section. To register an account, type @kbd{C-u M-x jabber-connect} and enter your desired JID in the form @samp{@var{username}@@@var{server}}. You will be presented with a registration form to fill out and send. There the username you chose will be prefilled. After registration, you can connect to the server as usual. @node Connecting, Chatting, Registering an account, Basic operation @section Connecting @findex jabber-connect-all @findex jabber-connect @findex jabber-disconnect-one @findex jabber-disconnect @cindex Connecting Now, type @kbd{C-x C-j C-c} and enter your JID and password. If you successfully connect, jabber.el will download your roster and display it in a buffer called @code{*-jabber-roster-*}. By default, you will appear as ``online'' to your contacts. To change this to e.g. ``away'', type @kbd{M-x jabber-send-presence} or @kbd{C-x C-j C-p}. @xref{Presence}, for more information. To disconnect, type @kbd{M-x jabber-disconnect} or @kbd{C-x C-j C-d}. Use @kbd{M-x jabber-disconnect-one} to disconnect just one account (or just type @kbd{C-u C-x C-j C-d}). If you don't want to type your JID every time you connect, you can save it in the variable @code{jabber-account-list}. @xref{Account settings}. If you configure more than one account, all of them will be connected when you type @kbd{C-x C-j C-c}, as that key is bound to @code{jabber-connect-all}. To connect only one account, possibly one that's not in your list, type @kbd{M-x jabber-connect} or @kbd{C-u C-x C-j C-c}. @node Chatting, Presence, Connecting, Basic operation @section Chatting @cindex Chatting @findex jabber-chat-with There are several ways to open a chat buffer. The shortest way is to put point over the person you want to chat with in the roster display and hit RET. You can also use the function @code{jabber-chat-with}. This function is bound to @kbd{C-x C-j C-j} in the global keymap. You will be asked to enter a JID in the minibuffer. You can also enter the roster name of one of your contacts. All JIDs and names in your roster can be tab-completed. You can also use menus to access commands. In the roster display, you can access several menus through keystrokes or mouse clicks. You can bring one big menu up by pressing the second mouse button, or you can bring up the ``chat menu'' by typing @kbd{C-c C-c}. If you do the latter while point is on a roster entry, that entry will be the default value when you are asked for whom to chat with. Now, try opening a chat with someone. A buffer named @code{*-jabber-chat-:-@var{person}-*} will be created and selected. Type your message at the end of the buffer, and hit @kbd{RET} to send it. To include a newline in your message, use @kbd{C-j}. When you receive a message from someone, you will see a red indicator in the mode line. You can click this indicator with the mouse, or type @kbd{C-x C-j C-l} to switch to the relevant buffer. @xref{Tracking activity}. @node Presence, Presence subscription, Chatting, Basic operation @section Presence @cindex Presence @cindex Sending presence @findex jabber-send-presence @findex jabber-send-default-presence @vindex jabber-default-show @vindex jabber-default-status @vindex jabber-default-priority @dfn{Presence} is the Jabber term for letting other people know that you are online, and additionally how ``available'' you are. There are three elements to presence: availability state (called ``show''), status message, and priority. Your show state may either be empty (meaning simply ``online''), or one of @code{away}, @code{xa}, @code{dnd} and @code{chat}, meaning ``away'', ``extended away'' (i.e. away for an extended period), ``do not disturb'', and ``free for chat'', respectively. This information is available to everyone subscribing to your presence, but technically it does not restrict anyone's actions. You can chat with people even if you claim to be away. The status message is a short text complementing your show status, such as ``at home'', ``working'', ``phone'', ``playing games'' or whatever you want. It is sent to everyone subscribing to your presence, but not all clients prominently display it to the user. The priority is only interesting if you are running more than one Jabber client at a time accessing the same account. @xref{Resources and priority}. To set your presence, use the function @code{jabber-send-presence} (bound to @kbd{C-x C-j C-p}). It can be called both interactively and in Lisp code. For the latter case, use something like @code{(jabber-send-presence "away" "idle for 10 minutes" 10)}. There are a few shortcuts: @table @kbd @item C-x C-j C-a Send ``away'' presence (with prefix argument, specify status text) @item C-x C-j C-x Send ``extended away'' presence (with prefix argument, specify status text) @item C-x C-j C-o Send default presence (see below) @end table By default, jabber.el sets your presence when you connect. If you want it not to do that, remove @code{jabber-send-current-presence} from @code{jabber-post-connect-hooks}. If you want to change the presence that is sent, change the variables @code{jabber-default-show}, @code{jabber-default-status} and @code{jabber-default-priority}. With jabber.el, you can set your presence remotely. @xref{Ad-Hoc Commands}. @menu * Resources and priority:: * Directed presence:: @end menu @node Resources and priority, Directed presence, Presence, Presence @subsection Resources and priority @cindex Resource @cindex Priority Every connection to an account has a specific name, a @dfn{resource}. The account itself has a JID of the form @samp{@var{username}@@@var{server}} (a @dfn{bare JID}), but the connections have JIDs of the form @samp{@var{username}@@@var{server}/@var{resource}} (a @dfn{full JID}). You can choose the resource name yourself by entering a JID of the latter form at the connection prompt (@pxref{Connecting}), or by configuring it in @code{jabber-account-list} (@pxref{Account settings}) Each session has a @dfn{priority}. The priority determines what happens when a message is sent to the bare JID (i.e. without specifying what connection should receive message). Such messages are delivered to the connection with the highest non-negative priority value. If there are no connections, or if all connections have negative priority, the message is either stored on the server for later delivery or bounced to the sender, depending on the server configuration. If there are several connections with the same priority, the behaviour depends on the server. Some server implementations deliver the message to all such connections, while others choose one connection depending on certain rules. Note that these rules do not apply when a message is sent to a full JID. Such messages are sent to the specified resource, if it is still connected, and otherwise treated as messages to the bare JID. In the chat buffers of jabber.el, messages are sent to whatever JID the last message came from (usually a full JID), or to the bare JID if no message has been received yet. Other clients may have different behaviour. @node Directed presence, , Resources and priority, Presence @subsection Directed presence @cindex directed presence @cindex send directed presence @findex jabber-send-directed-presence You can send ``directed presence'' with @kbd{M-x jabber-send-directed-presence}. This is mostly useful to manage transports---sending directed presence is a way to turn them on and off. You can also send directed presence to an annoying contact to appear as away or offline to that contact. Note, however, that in both of these cases, all subscribed entities will get your next global presence update. @node Presence subscription, Roster buffer, Presence, Basic operation @section Presence subscription @cindex Presence subscription @cindex Subscribing to someone's presence @findex jabber-send-subscription-request Having permission to view the presence status of a person is called @dfn{subscribing to his presence}. Presence subscription between two persons can be asymmetric. Subscription state is shown in the roster display by arrows (@pxref{Customizing the roster buffer}). A left-pointing arrow means that the contact can see your presence (``from''). A right-pointing arrow means that you can see the contact's presence (``to''). The most common case is mutual subscription, a double-ended arrow (``both''). When jabber.el receives a presence subscription request, it will present it to you in a chat buffer, and offer you to choose subscription mode and send a subscription request back to that person. The ``Mutual'' button accepts the request and sends a reciprocal request.@footnote{If this request is superfluous, the server will drop it without bothering the contact.} The ``One-way'' button accepts the request, but doesn't ask for a subscription in return. The ``Decline'' button declines the request. To request subscription to someone, type @kbd{M-x jabber-send-subscription-request}. You will be prompted for the JID to send it to. This command can also be accessed through the Roster menu, by typing @kbd{C-c C-r} in the roster buffer. After that, you will probably want to give the contact a more readable name. The command for that is @code{jabber-roster-change}, which is also available in the Roster menu or by typing @kbd{e} on a person in the roster buffer. @node Roster buffer, , Presence subscription, Basic operation @section The roster buffer @cindex Roster buffer, basics @cindex Menus @cindex Key bindings The roster buffer is called @code{*-jabber-roster-*}. It simply contains a list of the contacts on your roster. If you have several accounts connected, contacts will be grouped by account. In the roster buffer, any command which requires a JID will default to the JID under point when called. These commands can be called through either keyboard menus or mouse menus. To open a menu with the mouse, simply press the second mouse button over the JID in question.@footnote{For some reason, mouse menus don't work in XEmacs. Patches are welcome.} This will bring up a menu with all available actions. The keyboard menus are split into categories: Chat, Roster, Information, MUC (Multi-User Chat, or groupchat) and Services, opened by @kbd{C-c C-c}, @kbd{C-c C-r}, @kbd{C-c C-i}, @kbd{C-c C-m} and @kbd{C-c C-s}, respectively. @vindex jabber-roster-show-bindings A list of keybindings is displayed at the top of the roster buffer. You can turn it off by setting @code{jabber-roster-show-bindings} to nil. @findex jabber-display-roster You can call @code{jabber-display-roster} (bound to @kbd{g}) to redisplay your roster according to changed preferences (@pxref{Customizing the roster buffer}). This will not refetch your roster from the server. Refetching the roster is usually not needed, since updates are pushed to clients automatically. You can choose not to have the roster updated automatically on presence changes (@pxref{Presence alerts}). In that case, you need to call @code{jabber-display-roster} manually. @vindex jabber-show-offline-contacts @cindex Hiding offline contacts @cindex Offline contacts, hiding Please note, that by default offline contacts showed in roster as any others. To hide them, you can use @kbd{o} in roster buffer. To permanently hide them, customize @code{jabber-show-offline-contacts} variable. @node Groupchat, Composing messages, Basic operation, Top @chapter Groupchat @cindex Groupchat @cindex MUC @cindex Chatrooms The groupchat menu can be accessed by typing @kbd{C-c C-m} in the roster buffer. You can also type the commands directly, as will be shown here. @findex jabber-groupchat-join @cindex Joining a groupchat @cindex Changing nickname @cindex Nickname, changing To join a groupchat, type @kbd{M-x jabber-groupchat-join}. You will be prompted for the groupchat to join, and your nickname in the groupchat. This nickname doesn't need to have any correlation to your JID; in fact, groupchats are usually (but not always) configured such that only moderators can see your JID. You can change your nickname with @kbd{M-x jabber-muc-nick}. @xref{Configuration}, for setting default nicknames. @cindex Query groupchat @vindex jabber-muc-disable-disco-check When trying to join a room, jabber.el first sends a service discovery info request to the room, to find out whether it exists and what features are enabled (in particular whether the room is password-protected). However, this can cause problems with some buggy MUC services (or services that respond in a way that jabber.el doesn't expect). A workaround for that is to set @code{jabber-muc-disable-disco-check} to @code{t}; however, the bug should be unearthed and fixed. Groupchat messages will be displayed in a buffer called @code{*-jabber-groupchat-:-@var{groupchat}-*}. By default, the buffer name is based on the JID of the chat room. If you want a shorter name, you can add the chat room to your roster and give it a name, using the command @kbd{M-x jabber-roster-change}. The groupchat buffer works much like the chat buffer. It has its own class of alerts (@pxref{Customizing alerts}), and uses activity tracking (@pxref{Tracking activity}). @vindex jabber-muc-completion-delimiter @vindex jabber-muc-looks-personaling-symbols @cindex Groupchat completion @cindex Nick completion in groupchat Also, to save from repeating unnesesary typing you can press @kbd{Tab} key to complete nick of a groupchat member that you are talking with. You can customize your form of personal talking in MUC (@code{jabber-muc-completion-delimiter}) and form of personal talking to you (@code{jabber-muc-looks-personaling-symbols})---see ``jabber-chat'' customization group. Defaults are sane, so it is unlikely that you would want to change this, but... it is Emacs! @cindex Topic, MUC @findex jabber-muc-set-topic To change the topic of a groupchat, type @kbd{M-x jabber-muc-set-topic}. The current topic is shown in the header line. @findex jabber-groupchat-leave To leave a groupchat, type @kbd{M-x jabber-groupchat-leave}. @findex jabber-groupchat-get-config If you are the owner of a groupchat, you can change its configuration by typing @kbd{M-x jabber-groupchat-get-config}. A configuration form will be rendered in new buffer. @findex jabber-muc-names To see which people are in a groupchat, type @kbd{M-x jabber-muc-names}. This gives a list of nicknames, ``roles'', ``affiliations'', and possibly JIDs. @xref{MUC Administration}, for the meaning of roles and affiliations. @menu * Configuration:: * Invitations:: * Private messages:: * MUC Administration:: @end menu @node Configuration, Invitations, Groupchat, Groupchat @section Configuration @vindex jabber-muc-default-nicknames @vindex jabber-muc-autojoin @findex jabber-muc-autojoin @cindex Default MUC nickname @cindex Autojoin chat rooms @cindex Bookmarks, MUC @findex jabber-edit-bookmarks You can configure jabber.el to use a certain nickname for a certain room, or to automatically join a certain room when you connect. You can do this either by storing bookmarks on the server or by setting Emacs variables. Type @kbd{M-x jabber-edit-bookmarks} to add bookmarks. You can specify the JID of the conference, the name of the conference (not used by jabber.el), whether to automatically join the room, your desired nickname (or leave empty), and the room password (or leave empty). The default nickname for groupchats is the username part of your JID. If you don't use bookmarks, you can set different nicknames for different groups by customizing @code{jabber-muc-default-nicknames}. There you specify the JID of the group, and your preferred nickname. Automatically joining certain rooms when connecting can be accomplished by setting @code{jabber-muc-autojoin} to a list containing the JIDs of the rooms you want to enter. To disable this feature, remove @code{jabber-muc-autojoin} from @code{jabber-post-connect-hooks}. Please note, that @code{jabber-muc-default-nicknames} and @code{jabber-muc-autojoin} are machine-local, but apply to @emph{all} accounts---if you connect several accounts, both will try to connect to the same chat rooms, or use the same nickname. This will lead to confusion. @node Invitations, Private messages, Configuration, Groupchat @section Invitations @cindex Invitations @findex jabber-muc-invite You can invite someone to a groupchat with @kbd{M-x jabber-muc-invite} (also available in the MUC menu). Pay attention to the order of the arguments---as both users and rooms are just JIDs, it is technically possible to invite a room to a user, but that's probably not what you want. When you receive an invitation, it appears in the chat buffer along with two buttons, ``Accept'' and ``Decline''. Pressing ``Accept'' enters the room, as you would expect. Pressing ``Decline'' gives you an opportunity to state the reason why you're not joining. @node Private messages, MUC Administration, Invitations, Groupchat @section Private messages @cindex Private MUC messages @findex jabber-muc-private You can open a private chat with a participant in a chat room with @kbd{M-x jabber-muc-private} (or by using the MUC menu). This creates a buffer with the name @code{*-jabber-muc-priv-@var{group}-@var{nickname}-*} (customizable by @code{jabber-muc-private-buffer-format}), which behaves mostly like an ordinary chat buffer. This buffer will also be created if someone sends a private message to you. Private MUC messages use the same alerts as normal chat messages. @xref{Message alerts}. @node MUC Administration, , Private messages, Groupchat @section Administration Administration of a MUC room mostly consists of managing roles and affiliations. Roles are temporary, and apply until the user leaves the room. Affiliations are permanent, and based on JIDs. @subsection Roles @findex jabber-muc-set-role @cindex Kicking, MUC @cindex Voice, MUC @cindex Moderator, MUC @cindex Roles, MUC If you have moderator privileges, you can change the role of a participant with @kbd{M-x jabber-muc-set-role}. Kicking means setting the role to ``none''. Granting and revoking voice are ``participant'' and ``visitor'', respectively. ``moderator'' gives moderator privileges, obviously. The possible roles are: @table @samp @item moderator Has voice, can change other people's roles. @item participant Has voice. @item visitor Doesn't have voice (can't send messages to everyone, but can send private messages) @item none Not in room. @end table @subsection Affiliations @findex jabber-muc-set-affiliation @cindex Affiliations, MUC @cindex Banning, MUC If you have admin or owner privileges, you can change the affiliation of a user with @kbd{M-x jabber-muc-set-affiliation}. Affiliation is persistent, and based on JIDs. Depending of your affiliation and the MUC implementation, you might not be allowed to perform all kinds of changes, and maybe not in one step. Affiliations are: @table @samp @item owner Can destroy room, appoint admins, make people members, ban people. @item admin Can make people members or ban people. @item member Can enter the room, and has voice by default. @item none Rights depend on room configuration. The room might be members-only, or grant voice only to members. @item outcast Banned from the room. @end table @node Composing messages, File transfer, Groupchat, Top @chapter Composing messages @findex jabber-compose @cindex composing messages @cindex message composition The chat buffer interface can be inconvenient for some purposes. As you can't use @kbd{RET} to insert a newline (use @kbd{C-j} for that), writing a longer message can be painful. Also, it is not possible to include a subject in the message, or send the message to multiple recipients. These features are implemented by the message composing tool. Type @kbd{M-x jabber-compose} to start it. In the buffer that comes up, you can specify recipients, enter a subject, and type your message. @node File transfer, Services, Composing messages, Top @chapter File transfer @cindex File transfer @cindex Sending files jabber.el has limited support for file transfer. The most important limit is that files sent and received are kept in buffers, so Emacs must be able to allocate enough memory for the entire file, and the file size must be smaller than the maximum buffer size.@footnote{The maximum buffer size depends on in the variable @code{most-positive-fixnum}. On 32-bit systems, this is 128 or 256 megabytes, depending on your Emacs version.} jabber.el is able to exchange files with most Jabber clients (and also some MSN transports), but notably not with the official Google Talk client. The Google Talk client uses a different file transfer protocol which, at the time of this release, has not been published. @menu * Receiving files:: * Sending files:: @end menu @node Receiving files, Sending files, File transfer, File transfer @section Receiving files Receiving files requires no configuration. When someone wants to send a file to you, you are asked (through @code{yes-or-no-p}) whether you want to accept the file. If you answer yes, you get to choose where to save the file. If the sender's client is correctly configured (this is often not the case; see below), the file transfer will start. Currently, the only way to watch the progress is to inspect the buffer of the file being transfered; @kbd{C-x C-b} is one way of doing that. @xref{List Buffers, , Listing Existing Buffers, emacs, GNU Emacs Manual}. When the transfer is done, the message ``@var{file} downloaded'' appears in the echo area, and the buffer is killed. @c This truly sucks... If this doesn't happen, it is most likely the sender's fault. The sender needs to have a public IP address, either directly, through port forwarding (in which case the client needs to be configured with the real public IP address), or through an XEP-0065 proxy. If you have activated XML logging (@pxref{Debug options}), you can see the IP address that the other client is asking you to connect to there. Often you will find that this is an internal IP address (often starts with @code{192.168}). See the documentation of the sender's client for setting this up. @node Sending files, , Receiving files, File transfer @section Sending files @cindex proxy, file transfer @cindex file transfer proxy @cindex XEP-0065 proxy To send a file to someone, you need an XEP-0065 proxy.@footnote{This requirement is not inherent in the protocol, only in the current file transfer implementation of jabber.el, and in Emacs versions earlier than 22.} If your Jabber server hosts such a proxy, it will be found automatically, otherwise it needs to be manually configured. You can check whether your Jabber server has a proxy with @kbd{M-x jabber-get-disco-items}; see @ref{Service discovery}. @vindex jabber-socks5-proxies @findex jabber-socks5-query-all-proxies To configure a proxy manually, customize the variable @code{jabber-socks5-proxies}. Putting @code{proxy.jabber.se} there should work. Type @kbd{M-x jabber-socks5-query-all-proxies} to see if the proxies answer. @findex jabber-ft-send Now, you can type @kbd{M-x jabber-ft-send} to send a file to someone. You need to enter the correct full JID, including resource, to get this right. If the contact is logged in with only one client, and you can see it online, just typing the JID or roster name is enough. If you run the command from a chat buffer, the JID of the contact is given as the default value. If the contact has several clients online, you probably want to send the file to a particular one. If you run this command from within a chat buffer, the default target will be the one that last sent a message to you. If you just type a bare JID or a roster name, the client with the highest priority will get the file. If the contact accepts the file, and the contact's client succeeds in connecting to the proxy, jabber.el will send the file through the proxy. During this time, your Emacs will be blocked, so you might want to avoid sending large files over slow connections. @node Services, Personal information, File transfer, Top @chapter Services @cindex Browse buffers Not every Jabber entity is a physical person. There are many automatic entities, called servers, services, components, agents, transports and other names. The use of these is described here. The functions described in this chapter use @dfn{browse buffers}. Browse buffers are named @code{*-jabber-browse-:-@var{service}-*}, sometimes with a numerical suffix. The different menus have the same keybindings as in the roster buffer, and if you call a function operating on a JID while point is over a JID, that JID will be the default value, so you don't have to type it or copy it yourself. You can change the buffer name template by customizing the variable @code{jabber-browse-buffer-format}. @menu * Commands:: * Your home server:: * Transports:: * User directories:: * MUC services:: @end menu @node Commands, Your home server, Services, Services @section Commands A small number of commands is used for almost all interaction with Jabber services. Essentially, they are all the same: you request a form from the server, fill it in, and send it back. Most of these commands are available under the Service menu, which is opened by typing @kbd{C-c C-s}. Service discovery is under the Info menu instead, which is available under @kbd{C-c C-i}. @menu * Registration:: * Search:: * Ad-Hoc Commands:: * Service discovery:: * Browsing:: @end menu @node Registration, Search, Commands, Commands @subsection Registration @cindex Registration @findex jabber-get-register You can get a registration form for a service by typing @kbd{M-x jabber-get-register} and entering the JID of the service. On success, you get a single-stage form to fill in. There are two buttons at the bottom of the form, ``Submit'' and ``Cancel registration''. ``Submit'' does what you would expect it to, but ``Cancel registration'' cancels any existing registration with the service. Whichever of them you choose, you get a message in the echo area informing whether the operation succeeded. @node Search, Ad-Hoc Commands, Registration, Commands @subsection Search @cindex Search @findex jabber-get-search You can get a search form for a service by typing @kbd{M-x jabber-get-search}. This gives you a single-stage form to fill in. After you press the ``Submit'' button at the bottom, the search results will be displayed in the same buffer. @menu * Ad-Hoc Commands:: @end menu @node Ad-Hoc Commands, Service discovery, Search, Commands @subsection Ad-Hoc Commands @cindex Ad-Hoc Commands @findex jabber-ahc-get-list @findex jabber-ahc-execute-command jabber.el supports a subset of XEP-0050, the standard for Ad-Hoc Commands. As the name implies, this can be used for just about anything. In particular, it is used not only by services, but also by clients (e.g. Psi, and jabber.el itself). To find which commands are available, run ``Request command list'' (@code{jabber-ahc-get-list}).@footnote{This is the same thing as a disco items request to the node @code{http://jabber.org/protocol/commands}.} To run a command from the list, put point over it and run ``Execute command'' (@code{jabber-ahc-execute-command}), accepting the defaults for JID and node. (If you already know those, you could of course enter them yourself.) What happens next depends on the command and the service. In some cases, the service just responds that the command has been run. You may also get a form to fill out. This form may have multiple stages, in which case there are ``Next'' and ``Previous'' buttons for navigating between stages. You may also see ``Complete'', which runs the command skipping any remaining stages of the form, and ``Cancel'', which cancels the command. Currently, jabber.el uses ad-hoc commands for setting presence remotely. If you realize that you forgot to set your client to ``away'' with a low priority, you can do it remotely from any JID from @code{jabber-account-list}. So, you can add disabled JIDs in @code{jabber-account-list} to allow them control your presence.@footnote{Most Jabber servers also support kicking a client off the net by logging in with another client with exactly the same resource.} @node Service discovery, Browsing, Ad-Hoc Commands, Commands @subsection Service discovery @cindex Service discovery @findex jabber-get-disco-items @findex jabber-get-disco-info Service discovery is used to find information about servers, services and clients. There are two kinds of requests: find @dfn{info} about a Jabber entity---i.e. its identity and supported features---and find @dfn{items} related to an entity, where the definition of ``related'' is left to the entity itself. The commands to execute such requests are @code{jabber-get-disco-info} and @code{jabber-get-disco-items}, respectively. These commands can be accessed from the Info menu, which is opened by typing @kbd{C-c C-i}. The commands accept a JID and optionally a ``node''. The result of such a command is displayed in a browse buffer. For an info request, the result just lists the identities and features of the entity. For an item request, the related items are listed. The items may be JIDs, or JIDs with a node. If you put point on one of the items, its JID and node will be the default value for any Jabber command. If you think that the interface to service discovery is awkward and should be replaced with something better, you are completely right. @node Browsing, , Service discovery, Commands @subsection Browsing @cindex Browsing @findex jabber-get-browse Before service discovery, browsing was the way to find information about Jabber entities. Nowadays it is all but superseded, but jabber.el still supports it. You can use it by typing @kbd{M-x jabber-get-browse}. It works much like service discovery. @node Your home server, Transports, Commands, Services @section Your home server @cindex Password change @cindex Changing password @cindex Account removal @cindex Removing an account You can interact with your Jabber server to change your password or remove your account. Both of these can be accomplished by typing @kbd{M-x jabber-get-register} and typing the JID of your server; @pxref{Registration}. @node Transports, User directories, Your home server, Services @section Transports to other IM networks @cindex Gateways @cindex Transports @cindex MSN transport @cindex ICQ transport @cindex AIM transport Some Jabber services make it possible to communicate with users on other instant messaging networks (e.g. MSN, ICQ, AIM), in effect turning your Jabber client into a multi-protocol client. These are called @dfn{gateways} or @dfn{transports}. They work by impersonating you on the legacy network; therefore you need to provide your username and password through registration. @subsection Finding a transport To use such a transport, you first need to find one, obviously. Sometimes your home server provides the transports you need, but you are not limited to those; in principle you can use any transport on the Jabber network. Some transports only accept local users, though. Transports are generally mentioned on the web page of the Jabber server in question. You can also find transports from within the client; @pxref{Service discovery}. @subsection Registering with a transport To register with a transport, type @kbd{M-x jabber-get-register} and enter the JID of the transport. This will open a registration form where you get to fill in your login information; @pxref{Registration}. You can later use this same form to change the information or cancel your registration. After you have registered, the transport will request presence subscription. It needs that to know when you are online, and synchronize your presence on the legacy network. @subsection Contact list Once you are registered, the transport will transfer the contact list from the legacy service. From the Jabber side, it appears as if lots of people suddenly request presence subscription to you. This is somewhat inconvenient, but it is currently the only way that the transport can influence your Jabber contact list, as it is an entity external to your server.@footnote{Of course, jabber.el could do more to alleviate this inconvenience.} When you have accepted these presence subscriptions, the contacts from legacy networks appear as if they were Jabber contacts. @subsection Finding users Some legacy networks have a global database of users, and some transports support searching that database. In that case, you can search for other users with @kbd{M-x jabber-get-search}; @pxref{Search}. @node User directories, MUC services, Transports, Services @section User directories There are some Jabber user directories, usually abbreviated JUDs. The most well-known one is @samp{users.jabber.org}. You can register with such a directory to let other people find you (@pxref{Registration}), and you can search the directory (@pxref{Search}). @node MUC services, , User directories, Services @section MUC services MUC services (Multi-User Chat, chat rooms) are usually not operated by these commands, but by commands specific to the MUC protocol; @pxref{Groupchat}. However, some MUC services offer nickname registration through the registration protocol (@pxref{Registration}), and other commands; @pxref{Ad-Hoc Commands}. @node Personal information, Avatars, Services, Top @chapter Personal information @cindex vCard @cindex Personal information @findex jabber-vcard-get @findex jabber-vcard-edit The Jabber way of handling personal information (name, addresses, phone numbers, etc) is ``vCards'' encoded in XML.@footnote{@xref{XEP-0054}.} You can get information about a user by running @kbd{M-x jabber-vcard-get}, and you can edit your own information by running @kbd{M-x jabber-vcard-edit}. The form for editing your information can be slightly confusing---you are allowed to enter any number of addresses, phone numbers and e-mail addresses, each of which has a set of orthogonal properties. You can add and remove items with the @samp{[INS]} and @samp{[DEL]} buttons, respectively. This is also where you set your avatar (@pxref{Avatars}). The size of your avatar file is limited to 8 kilobytes. @node Avatars, Time queries, Personal information, Top @chapter Avatars @cindex avatars @vindex jabber-vcard-avatars-retrieve @vindex jabber-vcard-avatars-publish @vindex jabber-avatar-cache-directory @vindex jabber-chat-buffer-show-avatar jabber.el supports viewing and publishing avatars according to XEP-0153, vCard-Based Avatars. By default, if you have an avatar in your vCard (@pxref{Personal information}), it will be published for others to see, and if other people publish their avatars, they will be displayed in the roster buffer and in the header line of chat buffers, if your Emacs can display images. Otherwise, jabber.el will not fetch avatars at all. To disable retrieval of other people's avatars, set @code{jabber-vcard-avatars-retrieve} to nil. To disable publishing of your own avatar, set @code{jabber-vcard-avatars-publish} to nil. To disable avatars in chat buffer header lines, set @code{jabber-chat-buffer-show-avatar} to nil. There are a number of restrictions on avatar images in the specification. Most of them are not enforced by jabber.el. @itemize @bullet @item The image should be smaller than 8 kilobytes; this is enforced by jabber.el. @item The image height and width should be between 32 and 96 pixels; the recommended size is 64 by 64 pixels. @item The image should be square. @item The image should be in either PNG, GIF, or JPEG format. (jabber.el will behave incorrectly if the image is not in a format supported by Emacs.) @end itemize Avatars are cached in the directory specified by @code{jabber-avatar-cache-directory}, by default @file{~/.jabber-avatars/}. The cache is never cleaned, so you might want to do that yourself from time to time. @node Time queries, Useful features, Avatars, Top @chapter Time queries @cindex time query @findex jabber-get-time With @kbd{M-x jabber-get-time}, you can ask what time an entity (client, server or component) thinks it is, and what time zone it thinks it is in. @cindex last online @findex jabber-get-last-online You can query a server about when a certain user was last seen online. Use @kbd{M-x jabber-get-last-online} for that. @cindex uptime, query @cindex idle time, query @findex jabber-get-idle-time You can also ask a client about how long a user has been idle with @kbd{M-x jabber-get-idle-time}. Not all clients answer such queries, e.g. jabber.el doesn't. This command can also tell the uptime of a server or component. The first of these commands uses the old Entity Time protocol (@pxref{XEP-0090}). It has been superseded by XEP-0202, but jabber.el doesn't implement the newer protocol yet. The latter two commands use the Last Activity protocol (@pxref{XEP-0012}). @node Useful features, Message history, Time queries, Top @chapter Useful features jabber.el includes a number of features meant to improve the user interface and do other useful things. @menu * Autoaway:: * Modeline status:: * Keepalive:: * Reconnecting:: * Tracking activity:: * Watch buddies:: * Spell checking:: @end menu @node Autoaway, Modeline status, Useful features, Useful features @section Autoaway @cindex autoaway @cindex idle @cindex xprintidle @vindex jabber-autoaway-method It is possible to automatically set your status to ``away'' when you haven't used your computer for a while. This lets your contacts know that you might not answer immediately. To activate this feature, add @code{jabber-autoaway-start} to @code{jabber-post-connect-hooks}, e.g: @example (add-hook 'jabber-post-connect-hooks 'jabber-autoaway-start) @end example There are different methods to find how long you have been ``idle''. The method to use is specified by @code{jabber-autoaway-method}. The value of this variable should be a function that returns the number of seconds you have been idle. Three functions are provided. If your Emacs has the @code{current-idle-time} function (which was introduced in Emacs 22), it is used by default. Note that this method only measures the time since you last interacted with Emacs, and thus disregards activity in other programs. If you are using the X Window System, you can use the xprintidle program.@footnote{@uref{http://www.dtek.chalmers.se/~henoch/text/xprintidle.html}} Make sure that @code{jabber-xprintidle-program} is set to the correct file name. This uses the same method as @uref{http://www.jwz.org/xscreensaver,XScreensaver} to find your idle time. If you use the xscreensaver program, you can use the @file{xscreensaver-emacs-jabber} Perl script to synchronize xscreensaver and jabber.el status. It is a simple Perl daemon that watches for xscreensaver status and sets jabber.el's presence when needed. I.e.: it sets XA presence when the screen is blanked or locked (by hands or by idle timeout) and default presence when it's unlocked/unblanked. To use it, just run @file{xscreensaver-emacs-jabber} after xscreensaver and make sure that your Emacs run in server mode (that you run @code{(server-start)} in init files; @pxref{Emacs Server, , Using Emacs as a Server, emacs, GNU Emacs Manual}. Alternatively, you can turn on and off server-mode by jabber.el's hooks). If you are using Emacs on a GNU/Linux terminal, the function @code{jabber-termatime-get-idle-time} is used by default. It uses the access time of the terminal device as a measure of idle time. @node Modeline status, Keepalive, Autoaway, Useful features @section Modeline status @cindex Modeline @findex jabber-mode-line-mode @vindex jabber-mode-line-mode @vindex jabber-mode-line-compact By typing @kbd{M-x jabber-mode-line-mode} you toggle display of some status in mode lines. The information is your own presence status, and some numbers showing the status of your roster contacts. By default, there are three numbers, for ``online'' (chatty and online), ``away'' (away, extended away and do not disturb) and offline contacts. If you set @code{jabber-mode-line-compact} to nil, you get a complete breakdown of presence status. That gives you six numbers indicating the number of chatty, online, away, extended away, dnd, and offline contacts, respectively. @node Keepalive, Reconnecting, Modeline status, Useful features @section Keepalive @cindex Keepalive @cindex Detecting lost connections Sometimes network connections are lost without you noticing. This is especially true with Jabber, as it is quite reasonable to keep the connection open for a long time without either sending or receiving any data. On the other hand, the server may want to do the same kind of detection, and may expect the client to send something at regular intervals. If you want to detect a lost connection earlier, or make sure that the server doesn't drop your connection, you can use the keepalive functions. These come in two flavours: whitespace pings and XMPP pings. @subsection Whitespace pings @cindex Whitespace pings A @dfn{whitespace ping} is a single space character sent to the server. This is often enough to make NAT devices consider the connection ``alive'', and likewise for certain Jabber servers, e.g. Openfire. It may also make the OS detect a lost connection faster---a TCP connection on which no data is sent or received is indistinguishable from a lost connection. @findex jabber-whitespace-ping-start @findex jabber-whitespace-ping-stop Type @kbd{M-x jabber-whitespace-ping-start} to start it, and @kbd{M-x jabber-whitespace-ping-stop} to stop it. The former is in @code{jabber-post-connect-hooks} by default; @pxref{Hooks}. @vindex jabber-whitespace-ping-interval The frequency of whitespace pings is controlled by the variable @code{jabber-whitespace-ping-interval}. The default value is once every 30 seconds. @subsection XMPP pings These functions work by sending a ping request to your server once in a while (by default every ten minutes), and considering the connection lost if the server doesn't answer within reasonable time (by default 20 seconds). @findex jabber-keepalive-start @findex jabber-keepalive-stop Type @kbd{M-x jabber-keepalive-start} to start it, and @kbd{M-x jabber-keepalive-stop} to stop it. You may want to add @code{jabber-keepalive-start} to @code{jabber-post-connect-hooks}; @pxref{Hooks}. @vindex jabber-keepalive-interval @vindex jabber-keepalive-timeout You can customize the interval and the timeout with the variables @code{jabber-keepalive-interval} and @code{jabber-keepalive-timeout}, respectively. @node Reconnecting, Tracking activity, Keepalive, Useful features @section Reconnecting @cindex Reconnect @cindex Automatic reconnection @vindex jabber-auto-reconnect jabber.el supports automatic reconnection to Jabber server(s) upon lost connection. By default it is off. To turn on, customize the @code{jabber-auto-reconnect} variable. This is of limited use if you have to type your password every time jabber.el reconnects. There are two ways to save your password: you can set it in @code{jabber-account-alist} (@pxref{Account settings}), and you can use @file{password-cache.el}, which is available in recent versions of Gnus and in Emacs 23. Note that you probably want to customize @code{password-cache-expiry} if you use the latter. @node Tracking activity, Watch buddies, Reconnecting, Useful features @section Tracking activity @cindex Activity @findex jabber-activity-mode @vindex jabber-activity-make-strings @vindex jabber-activity-query-unread @vindex jabber-activity-count-in-title @vindex jabber-activity-count-in-title-format When you're working on something important you might want to delay responding to incoming messages. However, when you're done working, will you remember them? If you're anything like me, you'll have a lot of buffers in your Emacs session, and a Jabber chat buffer can easily get lost. When @code{jabber-activity-mode} is enabled (by default, it is), Emacs keeps track of the buddies which have messaged you since last you visited their buffer, and will display them in mode line. As soon as you visit their buffer they disappear from the mode line, indicating that you've read their message. If your mode line fills over because of these notifications, you can customize @code{jabber-activity-make-strings} to shorten them to the shortest possibly unambiguous form. If you try to exit Emacs while you still have unread messages, you will be notified and asked about this. If you don't like that, set @code{jabber-activity-query-unread} to nil. If you want to display the number of unread buffers in the frame title, set @code{jabber-activity-count-in-title} to t. The format of the number can be changed through @code{jabber-activity-count-in-title-format}. To hide activity notifications for some contacts, use @code{jabber-activity-banned} variable - just add boring JIDs (as regexps) here. For complete customizability, write a hook function for @code{jabber-activity-update-hook}. From that function, you can take action based on @code{jabber-activity-jids}, @code{jabber-activity-mode-string}, and @code{jabber-activity-count-string}. @node Watch buddies, Spell checking, Tracking activity, Useful features @section Watch buddies @cindex Watch @cindex Online notifications @findex jabber-watch-add @findex jabber-watch-remove Sometimes you might be waiting for a certain person to come online, and you don't want that occasion to get lost in the noise. To get an obtrusive message when that happens, type @kbd{M-x jabber-watch-add} and select the person in question. You can enter a comment, to remember why you added the watch. You will get a message whenever that person goes from offline to online. jabber.el will remember this for the rest of your Emacs session (it's not saved to disk, though), but if you want to get rid of it, type @kbd{M-x jabber-watch-remove}. @node Spell checking, , Watch buddies, Useful features @section Spell checking @cindex flyspell @cindex Spell checking You can activate spell checking in a chat buffer with @kbd{M-x flyspell-mode}. It will check only what you are currently writing, not what you receive or what you have already sent. You may want to add @code{flyspell-mode} to @code{jabber-chat-mode-hook}. For more information about Emacs spell checking, @pxref{Spelling, , Checking and Correcting Spelling, emacs, GNU Emacs Manual}. @node Message history, Typing notifications, Useful features, Top @chapter Message history @cindex History @cindex Backlog @findex jabber-truncate-top @findex jabber-truncate-muc @findex jabber-truncate-chat @vindex jabber-history-enabled @vindex jabber-global-history-filename @vindex jabber-use-global-history @vindex jabber-history-dir @vindex jabber-history-enable-rotation @vindex jabber-history-size-limit @vindex jabber-backlog-number @vindex jabber-backlog-days @vindex jabber-log-lines-to-keep If you want a record of messages sent and received, set @code{jabber-history-enabled} to t. By default all messages will be saved to a global history file specified by @code{jabber-global-history-filename} (@file{~/.jabber_global_message_log} by default). If you prefer to store your chats' history in per-contact files, you can set @code{jabber-use-global-history} to @code{nil}. When using per-contact history, files are named by the contact JID and saved under the directory specified by the variable @code{jabber-history-dir} (default is @file{~/.emacs-jabber}). When you open a new chat buffer and have entries in your history file, the last few messages you recently exchanged with the contact in question will be inserted. You can control how many messages with @code{jabber-backlog-number} (by default 10), and how old messages with @code{jabber-backlog-days} (by default 3 days). @findex jabber-chat-display-more-backlog If you want to see more messages, use the function @code{jabber-chat-display-more-backlog}, available in the Chat menu. This is currently the only way to view the message history, apart from opening the history files manually. @cindex Rotation of history files @cindex History file rotation If you worry about your history file(s) size, you can enable history rotation feature by setting the variable @code{jabber-history-enable-rotation} to @code{t} (default is @code{nil}). This feature ``rotates'' your history files according to the following rule: When @code{jabber-history-size-limit} (in kilobytes) is reached, the @var{history-file} is renamed to @file{@var{history-file}-@var{number}}, where @var{number} is 1 or the smallest number after the last rotation. For example, suppose you set the @code{jabber-history-size-limit} variable to 512 and you chat with your buddy @samp{foo@@jabber.server} using the per-contact strategy to store history files. So, when the history file (@file{foo@@jabber-server}) reaches 512K bytes, it will be renamed to @file{foo@@jabber-server-1} and @file{foo@@jabber-server} will be set empty. Next time @file{foo@@jabber-server} grows to 512K bytes, it will be saved as @file{foo@@jabber-server-2} and so on. Although the example was presented with the per-contact history file strategy, history rotation works for both per-contact and global history logging strategies. @cindex Truncate @cindex Truncation If you also want to keep chat and groupchat buffers from growing too much, you can customize @code{jabber-alert-message-hooks} and @code{jabber-alert-muc-hooks} by adding truncation upon receiving message (@code{jabber-truncate-chat} and @code{jabber-truncate-muc}, respectively). The truncation limit may be set by customizing the variable @code{jabber-log-lines-to-keep}. @node Typing notifications, Roster import and export, Message history, Top @chapter Typing notifications There are two protocols for ``contact is typing'' notifications in Jabber. jabber.el supports both of them, displaying various information in the header line of chat buffers. @section Message events @cindex Composing @cindex Delivered @cindex Displayed @vindex jabber-events-request-these @vindex jabber-events-confirm-delivered @vindex jabber-events-confirm-displayed @vindex jabber-events-confirm-composing The older protocol is called Message Events (@pxref{XEP-0022}). Besides typing notification, it lets you know what happens to the messages you send. These states are possible: @itemize @bullet @item @samp{In offline storage} (the user will receive it on next logon) @item @samp{Delivered} to user's client (but not necessarily displayed) @item @samp{Displayed} to user @item User is @samp{typing a message} @end itemize The first state is only reported by servers; the other three are reported by clients. jabber.el can report all three of them, and can display all four; not all clients support all states, though. If you don't want jabber.el to send out this information about you, set the variables @code{jabber-events-confirm-delivered}, @code{jabber-events-confirm-displayed}, and/or @code{jabber-events-confirm-composing} to nil. You can make jabber.el not to request such information by customizing @code{jabber-events-request-these}. @section Chat states @vindex jabber-chatstates-confirm The newer protocol is called Chat States (@pxref{XEP-0085}). Rather than dealing with individual messages, it describes the state of the chat session between two people. The following states are possible: @itemize @bullet @item Active (the default state, not displayed) @item Inactive @item Composing @item Paused (i.e., taking a short pause in composing) @item Gone @end itemize jabber.el can display all five states, but only ever sends ``active'' and ``composing'' itself. To customize sending of chat states, customize the variable @code{jabber-chatstates-confirm}. @node Roster import and export, XMPP URIs, Typing notifications, Top @chapter Roster import and export @findex jabber-export-roster @findex jabber-import-roster @cindex Export roster @cindex Import roster Your roster is saved on the Jabber server, and usually not in the client. However, you might want to save the roster to a file anyway. The most common reason for this is probably to copy it to another account. To export your roster to a file, type @kbd{M-x jabber-export-roster}. A buffer will appear in which you can edit the data to be exported. Changes done in that buffer will not affect your real roster. To import your roster from a file, type @kbd{M-x jabber-import-roster}. You will be able to edit the data before importing it. Items not in the roster will be added; items in the roster will be modified to match imported data. Subscriptions will be updated. The format of the roster files is the XML used by roster pushes in the XMPP protocol, in UTF-8 encoding. @node XMPP URIs, Customization, Roster import and export, Top @chapter XMPP URIs @cindex URIs @cindex URLs @cindex links @cindex xmpp: links @cindex Mozilla integration @cindex web browser integration @cindex browser integration @findex jabber-handle-uri Many web page authors use links starting with @samp{xmpp:} for JIDs. Your web browser could be made to pass such links to jabber.el, so that such links are actually useful and not just decoration. How to do that depends on your operating system and web browser. For any of these methods, you need to make sure that you are running the Emacs server. @xref{Emacs Server, , Using Emacs as a Server, emacs, GNU Emacs Manual}, though the simplest way to start it is to customize the variable @code{server-mode}. @section GNOME The jabber.el distribution contains a GConf schema which tries to set up handling of @samp{xmpp:} URIs. It is installed by @samp{make install}. This may or may not work, depending on your GConf configuration and other installed applications. To check, try running: @example gconftool --get /desktop/gnome/url-handlers/xmpp/command @end example This should print something like: @example /usr/local/libexec/emacs-jabber-uri-handler "%s" @end example This setting is picked up by most GNOME or GTK based web browsers, including Firefox. @section Mozilla and Unix If you use a Mozilla-based web browser on a Unix-like operating system, and the GConf method above doesn't work, you can set it up manually by following these steps: @enumerate @item Note the path of the @file{emacs-jabber-uri-handler} file in the jabber.el distribution, and make sure it is executable. @item Set the Mozilla preference @samp{network.protocol-handler.app.xmpp} to the path of @file{emacs-jabber-uri-handler}. There are two ways to do this: @itemize @item Go to the URL @samp{about:config}, right-click in the list, choose ``New string'', and enter @samp{network.protocol-handler.app.xmpp} and the path in the following dialogs. @item Open or create the file @file{user.js} in your Mozilla profile directory (in the same directory as @file{prefs.js}), and add the following line: @example user_pref("network.protocol-handler.app.xmpp", "@var{/path/to}/emacs-jabber-uri-handler"); @end example Restart Mozilla for this change to take effect. @end itemize @end enumerate @section Other systems If you know how to pass an XMPP URI from your browser to the function @code{jabber-handle-uri}, your contribution for this section would be appreciated. @node Customization, Hacking and extending, XMPP URIs, Top @chapter Customization @findex jabber-customize @cindex Customization jabber.el is intended to be customizable for many tastes. After all, this is Emacs. To open a customization buffer for jabber.el, type @kbd{M-x jabber-customize}. @menu * Account settings:: * Menu:: * Customizing the roster buffer:: * Customizing the chat buffer:: * Customizing alerts:: * Hooks:: * Debug options:: @end menu @node Account settings, Menu, Customization, Customization @section Account settings @cindex Username @cindex Resource @cindex Password @cindex JID @cindex Network server @vindex jabber-account-list All account settings reside in the variable @code{jabber-account-list}. Usually you only need to set the JID, in the form @samp{username@@server} (or @samp{username@@server/resource} to use a specific resource name). These are the other account options: @table @asis @item Disabled If the account is disabled, @code{jabber-connect-all} will not attempt to connect it. You can still connect it manually with @code{jabber-connect}. @item Password You can set the password of the account, so you don't have to enter it when you connect. Note that it will be stored unencrypted in your customization file. @item Network server If the JID of the Jabber server is not also its DNS name, you may have to enter the real DNS name or IP address of the server here. @item Connection type This option specifies whether to use an encrypted connection to the server. Usually you want ``STARTTLS'' (@code{starttls}), which means that encryption is activated if the server supports it. The other possibilities are ``unencrypted'' (@code{network}), which means just that, and ``legacy SSL/TLS'' (@code{ssl}), which means that encryption is activated on connection. @item Port If the Jabber server uses a nonstandard port, specify it here. The default is 5222 for STARTTLS and unencrypted connections, and 5223 for legacy SSL connections. @end table @subsection For Google Talk @cindex Google Talk If you have a very new version of @file{dns.el},@footnote{Specifically, you need Emacs 23, or No Gnus 0.3.} you can connect to Google Talk just by specifying your Gmail address as JID. Otherwise, you also need to set ``network server'' to @kbd{talk.google.com} and ``connection type'' to ``legacy SSL''. @subsection Upgrade note Previous versions of jabber.el had the variables @code{jabber-username}, @code{jabber-server}, @code{jabber-resource} and @code{jabber-password}. These are now obsolete and not used. @node Menu, Customizing the roster buffer, Account settings, Customization @section Menu @vindex jabber-display-menu @cindex Menus There is a Jabber menu on the menu bar with some common commands. By default, it is displayed only if you are connected, or if you have configured any accounts. You can set the variable @code{jabber-display-menu} to @code{t} or @code{nil}, to have the menu displayed always or never, respectively. The default behaviour corresponds to the setting @code{maybe}. @findex jabber-menu Earlier, the way to have the menu appear was to call the function @code{jabber-menu}. It still works, but is considered obsolete. @node Customizing the roster buffer, Customizing the chat buffer, Menu, Customization @section Customizing the roster buffer @cindex Roster buffer, customizing @cindex Sorting the roster @vindex jabber-roster-sort-functions @code{jabber-roster-sort-functions} controls how roster items are sorted. By default, contacts are sorted first by presence, and then alphabetically by displayed name. @vindex jabber-sort-order @code{jabber-sort-order} controls how roster items are sorted by presence. It is a list containing strings corresponding to show status (@pxref{Presence}) or @code{nil}, which represents offline. @vindex jabber-show-resources @code{jabber-show-resources} controls when your contacts' resources are shown in the roster buffer. The default is to show resources when a contact has more than one connected resource. @vindex jabber-roster-line-format @code{jabber-roster-line-format} specifies how the entry for each contact looks. It is a string where some characters are special if preceded by a percent sign: @table @code @item %a Avatar of contact, if any @item %c @samp{*} if the contact is connected, or @samp{ } if not @item %u Subscription state---see below @item %n Nickname of contact, or JID if no nickname @item %j Bare JID of contact (without resource) @item %r Highest-priority resource of contact @item %s Availability of contact as a string ("Online", "Away" etc) @item %S Status string specified by contact @end table @code{jabber-roster-show-title} controls whether to show a "Jabber roster" string at the top of the roster buffer. You need to run @kbd{M-x jabber-display-roster} after changing this variable to update the display. @code{%u} is replaced by one of the strings given by `jabber-roster-subscription-display'. @vindex jabber-resource-line-format @code{jabber-resource-line-format} is nearly identical, except that the values correspond to the values of the resource in question, and that the @code{%p} escape is available, which inserts the priority of the resource. @vindex jabber-roster-buffer @code{jabber-roster-buffer} specifies the name of the roster buffer. If you change this, the new name will be used the next time the roster is redisplayed. @vindex jabber-roster-show-bindings @code{jabber-roster-show-bindings} controls whether to show a list of keybindings at the top of the roster buffer. You need to run @kbd{M-x jabber-display-roster} after changing this variable to update the display. @node Customizing the chat buffer, Customizing alerts, Customizing the roster buffer, Customization @section Customizing the chat buffer @cindex Chat buffer @cindex Timestamps @cindex Faces, chat buffer You can customize the look of the prompts in the chat buffer. There are separate settings for local text (i.e. what you write) and foreign text (i.e. what other people write). @vindex jabber-chat-text-local @vindex jabber-chat-text-foreign @code{jabber-chat-text-local} and @code{jabber-chat-text-foreign} determine the faces used for chat messages. @vindex jabber-chat-prompt-local @vindex jabber-chat-prompt-foreign @code{jabber-chat-prompt-local} and @code{jabber-chat-prompt-foreign} determine the faces used for the prompts. @vindex jabber-chat-local-prompt-format @vindex jabber-chat-foreign-prompt-format @code{jabber-chat-local-prompt-format} and @code{jabber-chat-foreign-prompt-format} determine what text is displayed in the prompts. They are format strings, with the following special sequences defined: @table @code @item %t The time when the message was sent or received @item %n The nickname of the user. For the foreign prompt, this is the name of the contact in the roster, or the JID if no name set. For the local prompt, this is the username part of your JID. @item %u The username of the user (i.e. the first part of the JID). @item %r The resource. @item %j The bare JID of the user @end table @cindex Timestamp format @vindex jabber-chat-time-format @code{jabber-chat-time-format} defines how @code{%t} shows time. Its format is identical to that passed to @code{format-time-string}. @xref{Time Conversion, , Time Conversion, elisp, GNU Emacs Lisp Reference Manual}. @vindex jabber-chat-delayed-time-format @code{jabber-chat-delayed-time-format} is used instead of @code{jabber-chat-time-format} for delayed messages (messages sent while you were offline, or fetched from history). This way you can have short timestamps everywhere except where you need long ones. You can always see the complete timestamp in a tooltip by hovering over the prompt with the mouse. @cindex Rare timestamps @vindex jabber-print-rare-time @vindex jabber-rare-time-format @vindex jabber-chat-text-local By default, timestamps are printed in the chat buffer every hour (at ``rare'' times). This can be toggled with @code{jabber-print-rare-time}. You can customize the displayed time by setting @code{jabber-rare-time-format}. Rare timestamps will be printed whenever time formatted by that format string would change. @cindex Header line of chat buffers @vindex jabber-chat-header-line-format @vindex jabber-muc-header-line-format You can also customize the header line of chat buffers, by modifying the variable @code{jabber-chat-header-line-format}. The format of that variable is the same as that of @code{mode-line-format} and @code{header-line-format}. @xref{Mode Line Format, , Mode-Line Format, elisp, GNU Emacs Lisp Reference Manual}. For MUC buffers, @code{jabber-muc-header-line-format} is used instead. @vindex jabber-chat-fill-long-lines @cindex Filling long lines in chat buffer The variable @code{jabber-chat-fill-long-lines} controls whether long lines in the chat buffer are wrapped. @node Customizing alerts, Hooks, Customizing the chat buffer, Customization @section Customizing alerts @cindex Alert hooks @findex define-jabber-alert When an event happens (currently including presence changes, incoming messages, and completed queries) you will usually want to be notified. Since tastes in this area vary wildly, these alerts are implemented as hooks, so you can choose which ones you want, or write your own if none fit. Actually, if you don't want to write your own, stop reading this section and just read @ref{Standard alerts}. Many kinds of alerts consist in displaying a text message through a certain mechanism. This text message is provided by a function which you can rewrite or replace. If this function returns @code{nil}, no message is displayed, and non-textual alerts refrain from action. If you want to write alert hooks that do nothing except displaying the supplied message in some way, use the macro @code{define-jabber-alert}. For example, if @var{foo} is a function that takes a string as an argument, write @example (define-jabber-alert foo "Display a message in a fooish way" 'foo) @end example @noindent and all details will be taken care of for you. The hooks take different arguments depending on category. However, they all have in common that the last argument is the result of the message function. The message function for each category takes the same arguments as the corresponding hooks, except for that last argument. Alert hook contributions are very welcome. You can send them to the mailing list, or to the Sourceforge patch tracker. Alert hooks are meant for optional UI things, that are subject to varying user tastes, and that can be toggled by simply adding or removing the function to and from the hook. For other purposes, there are corresponding general hooks, that are defvars instead of defcustoms, and that are meant to be managed by Lisp code. They have the same name as the alert hooks minus the @code{-alert} part, e.g. @code{jabber-message-hooks} vs @code{jabber-alert-message-hooks}, etc. @menu * Standard alerts:: * Presence alerts:: * Message alerts:: * MUC alerts:: * Info alerts:: @end menu @node Standard alerts, Presence alerts, Customizing alerts, Customizing alerts @subsection Standard alerts @cindex Alerts @cindex Scroll Thirteen alerts are already written for all four alert categories. These all obey the result from the corresponding message function. The @code{beep} alerts simply sound the terminal bell by calling @code{ding}. They are disabled by default. The @code{echo} alerts display a message in the echo area by calling @code{message}. They are enabled by default. The @code{switch} alerts switch to the buffer where the event occurred (chat buffer for incoming messages, roster buffer for presence changes, browse buffer for completed queries). They are disabled by default. Take care when using them, as they may interrupt your editing. The @code{display} alerts display but do not select the buffer in question, using the function @code{display-buffer}. @xref{Choosing Window, , Choosing a Window for Display, elisp, GNU Emacs Lisp Reference Manual}, for information about customizing its behaviour. This is enabled by default for info requests. @cindex Sound effects The @code{wave} alerts play a sound file by calling @code{play-sound-file}. No sound files are provided. To use this, enter the names of the sound files in @code{jabber-alert-message-wave}, @code{jabber-alert-presence-wave} and @code{jabber-alert-info-wave}, respectively. You can specify specific sound files for contacts matching a regexp in the variables @code{jabber-alert-message-wave-alist} and @code{jabber-alert-presence-wave-alist}. @cindex Screen terminal manager The @code{screen} alerts send a message through the Screen terminal manager@footnote{See @uref{http://www.gnu.org/software/screen/}.}. They do no harm if called when you don't use Screen. @cindex Ratpoison window manager @cindex Window manager, Ratpoison The @code{ratpoison} alerts send a message through the Ratpoison window manager@footnote{See @uref{http://ratpoison.sourceforge.net/}.}. They do no harm if used when you're not running X, but if you are running X with another window manager, the ratpoison processes will never exit. Emacs doesn't hold on to them, though. @cindex Sawfish window manager @cindex Window manager, Sawfish The @code{sawfish} alerts send a message through the Sawfish window manager. @cindex wmii window manager @cindex Window manager, wmii The @code{wmii} alerts display a message through the wmii window manager. @cindex xmessage @vindex jabber-xmessage-timeout The @code{xmessage} alerts send a message through the standard @code{xmessage} tool. The variable @code{jabber-xmessage-timeout} controls how long the alert appears. @cindex OSD The @code{osd} alerts send a message onto your screen using XOSD.@footnote{XOSD can be found at @uref{http://www.ignavus.net/software.html}. You also need @file{osd.el} from @uref{http://www.brockman.se/software/osd.el}.} @cindex libnotify @cindex notification-daemon The @code{libnotify} alerts send a message onto your screen using @code{notification-daemon}. @cindex Festival speech synthesis @cindex Speech synthesis, Festival The @code{festival} alerts speak the message using the Emacs interface of the Festival speech synthesis system@footnote{See @uref{http://www.cstr.ed.ac.uk/projects/festival/}.}. @cindex Autoanswerer The @code{autoanswer} alert is kind of special: it will not show you message/muc alert, but instead will automaticaly answer to sender. See variable `jabber-autoanswer-alist' description for details. @cindex Scroll chat buffers Additionally, for one-to-one and MUC messages, there are @code{scroll} alerts (enabled by default), that aim to do the right thing with chat buffers that are visible but not active. Sometimes you want point to scroll down, and sometimes not. These functions should do what you mean; if they don't, it's a bug. Also, in MUC you can use a family of so-called ``personal'' alerts. They are like other MUC alerts, but fire only on incoming messages addresed directly to you (also known as ``private messages''). One example of such an alert is @code{jabber-muc-echo-personal}, which shows a note for an MUC message only if it was addressed to you. Some of these functions are in the @file{jabber-alert.el} file, and the others are in their own files. You can use them as templates or inspiration for your own alerts. @node Presence alerts, Message alerts, Standard alerts, Customizing alerts @subsection Presence alerts @vindex jabber-alert-presence-message-function @findex jabber-presence-default-message Set @code{jabber-alert-presence-message-function} to your desired function. This function should look like: @example (defun @var{function} (@var{who} @var{oldstatus} @var{newstatus} @var{statustext}) ... ) @end example @var{who} is the JID symbol (@pxref{JID symbols}), @var{oldstatus} and @var{newstatus} are the previous and current stati, respectively, and @var{statustext} is the status message if provided, otherwise nil. @var{oldstatus} and @var{newstatus} can be one of @code{""} (i.e. online), @code{"away"}, @code{"xa"}, @code{"dnd"}, @code{"chat"}, @code{"error"} and @code{nil} (i.e. offline). @var{newstatus} can also be one of @code{"subscribe"}, @code{"subscribed"}, @code{"unsubscribe"} and @code{"unsubscribed"}. The default function, @code{jabber-presence-default-message}, returns @code{nil} if @var{oldstatus} and @var{newstatus} are the same, and in other cases constructs a message from the given data. Another function, @code{jabber-presence-only-chat-open-message}, behave just like @code{jabber-presence-default-message}, but only if conversation buffer for according JID is already open. Use it to show presence notifications only for ``interesting'' contacts. All presence alert hooks take the same arguments plus the additional @var{proposed-alert}, which is the result of the specified message function. This last argument is usually the only one they use. @node Message alerts, MUC alerts, Presence alerts, Customizing alerts @subsection Message alerts @vindex jabber-alert-message-function @findex jabber-message-default-message Set @code{jabber-alert-message-function} to your desired function.@footnote{Logically it should be @code{jabber-alert-message-message-function}, but that would be really ugly.} This function should look like: @example (defun @var{function} (@var{from} @var{buffer} @var{text}) ... ) @end example @var{from} is the JID symbol (@pxref{JID symbols}), @var{buffer} is the buffer where the message is displayed, and @var{text} is the text of the message. The default function, @code{jabber-message-default-message}, returns ``Message from @var{person}'', where @var{person} is the name of the person if specified in the roster, otherwise the JID. All message alert hooks take the same arguments plus the additional @var{proposed-alert}, which is the result of the specified message function. @vindex jabber-message-alert-same-buffer If you don't want message alerts when the chat buffer in question is already the current buffer, set @code{jabber-message-alert-same-buffer} to nil. This affects the behaviour of the default message function, so you'll have to reimplement this functionality if you write your own message function. @node MUC alerts, Info alerts, Message alerts, Customizing alerts @subsection MUC alerts @vindex jabber-alert-muc-function @vindex jabber-muc-alert-self @findex jabber-muc-default-message Set @code{jabber-alert-muc-function} to your desired function. This function should look like: @example (defun @var{function} (@var{nick} @var{group} @var{buffer} @var{text}) ... ) @end example @var{nick} is the nickname, @var{group} is the JID of the group, @var{buffer} is the buffer where the message is displayed, and @var{text} is the text of the message. The default function, @code{jabber-muc-default-message}, returns ``Message from @var{nick} in @var{group}'' or ``Message in @var{group}'', the latter for messages from the room itself. All MUC alert hooks take the same arguments plus the additional @var{proposed-alert}, which is the result of the specified message function. By default, no alert is made for messages from yourself. To change that, customize the variable @code{jabber-muc-alert-self}. @node Info alerts, , MUC alerts, Customizing alerts @subsection Info alerts @vindex jabber-alert-info-message-function @findex jabber-info-default-message Info alerts are sadly underdeveloped. The message function, @code{jabber-alert-info-message-function}, takes two arguments, @var{infotype} and @var{buffer}. @var{buffer} is the buffer where something happened, and @var{infotype} is either @code{'roster} for roster updates, or @code{'browse} for anything that uses the browse buffer (basically anything except chatting). The info alert hooks take an extra argument, as could be expected. @node Hooks, Debug options, Customizing alerts, Customization @section Hooks jabber.el provides various hooks that you can use for whatever purpose. @table @code @vindex jabber-post-connect-hooks @item jabber-post-connect-hooks This hook is called after successful connection and authentication. By default it contains @code{jabber-send-current-presence} (@pxref{Presence}). The hook functions get the connection object as argument. @vindex jabber-lost-connection-hooks @item jabber-lost-connection-hooks This hook is called when you have been disconnected for unknown reasons. Usually this isn't noticed for quite a long time. The hook is called with one argument: the connection object. @vindex jabber-pre-disconnect-hook @item jabber-pre-disconnect-hook This hook is called just before voluntary disconnection, i.e. in @code{jabber-disconnect}, the command to disconnect all accounts. There is currently no hook for disconnection of a single account. @vindex jabber-post-disconnect-hook @item jabber-post-disconnect-hook This hook is called after disconnection of any kind, possibly just after @code{jabber-lost-connection-hook}. @vindex jabber-chat-mode-hook @item jabber-chat-mode-hook This hook is called when a new chat buffer is created. @vindex jabber-browse-mode-hook @item jabber-browse-mode-hook This hook is called when a new browse buffer is created. @vindex jabber-roster-mode-hook @item jabber-roster-mode-hook This hook is called when the roster buffer is created. @end table @node Debug options, , Hooks, Customization @section Debug options These settings provide a lot of information which is usually not very interesting, but can be useful for debugging various things. @vindex jabber-debug-log-xml @cindex XML log @code{jabber-debug-log-xml} activates XML logging. All XML stanzas sent and received are logged in the buffer @code{*-jabber-xml-log-@var{jid}-*} in list format. @xref{XML representation}. @vindex jabber-debug-keep-process-buffers Usually, the process buffers for Jabber connections are killed when the connection is closed, as they would otherwise just fill up memory. However, they might contain information about why the connection was lost. To keep process buffers, set @code{jabber-debug-keep-process-buffers} to @code{t}. @node Hacking and extending, Protocol support, Customization, Top @chapter Hacking and extending This part of the manual is an attempt to explain parts of the source code. It is not meant to discourage you from reading the code yourself and trying to figure it out, but as a guide on where to look. Knowledge of Jabber protocols is assumed. @menu * Connection object:: * XML representation:: * JID symbols:: * Listening for new requests:: * Sending new requests:: * Extending service discovery:: * Chat printers:: * Stanza chains:: @end menu @node Connection object, XML representation, Hacking and extending, Hacking and extending @section Connection object @cindex connection object @cindex account object @cindex FSM Each Jabber connection is represented by a ``connection object''. This object has the form of a finite state machine, and is realized by the library @code{fsm}.@footnote{So far, this library is only distributed with jabber.el. The author hopes that it could be useful for other projects, too.} The various states of this object are defined in @file{jabber-core.el}. They describe the way of the connection through the establishing of a network connection and authentication, and finally comes to the @code{:session-established} state where ordinary traffic takes place. These details are normally opaque to an extension author. As will be noted, many functions expect to receive a connection object, and functions at extension points generally receive such an object in order to pass it on. The following functions simply query the internal state of the connection: @defun jabber-connection-jid connection The @code{jabber-connection-jid} function returns the full JID of @var{connection}, i.e. a string of the form @code{"username@@server/resource"}. @end defun @defun jabber-connection-bare-jid connection The @code{jabber-connection-bare-jid} function returns the bare JID of @var{connection}, i.e. a string of the form @code{"username@@server"}. @end defun @node XML representation, JID symbols, Connection object, Hacking and extending @section XML representation @cindex XML representation The XML representation is the one generated by @file{xml.el} in Emacs, namely the following. Each tag is a list. The first element of the list is a symbol, the name of which is the name of the tag. The second element is an alist of attributes, where the keys are the attribute names in symbol form, and the values are strings. The remaining elements are the tags and data contained within the tag. For example, @example Fnord @end example is represented as @example (foo ((bar . "baz")) (frobozz nil "") "Fnord ") @end example Note the empty string as the third element of the @code{frobozz} list. It is not present in newer (post-21.3) versions of @file{xml.el}, but it's probably best to assume it might be there. @defun jabber-sexp2xml xml-sexp This function takes a tag in list representation, and returns its XML representation as a string. You will normally not need to use this function directly, but it can be useful to see how your sexps will look when sent to the outer, non-Lisp, world. @end defun @defun jabber-send-sexp connection sexp This function sends @var{sexp}, an XMPP stanza in list representation, and sends it over @var{connection}. You will normally use the functions @code{jabber-send-presence}, @code{jabber-send-message} and @code{jabber-send-iq} instead of this function. @end defun @node JID symbols, Listening for new requests, XML representation, Hacking and extending @section JID symbols @vindex jabber-jid-obarray JIDs are sometimes represented as symbols. Its name is the JID, and it is interned in @code{jabber-jid-obarray}. A roster entry can have the following properties: @table @code @item xml The XML tag received from the server on roster update @item name The name of the roster item (just like the XML attribute) @item subscription The subscription state; a string, one of @code{"none"}, @code{"from"}, @code{"to"} and @code{"both"} @item ask The ask state; either @code{nil} or @code{"subscribe"} @item groups A list of strings (possibly empty) containing all the groups the contact is in @item connected Boolean, true if any resource is connected @item show Presence show value for highest-priority connected resource; a string, one of @code{""} (i.e. online), @code{"away"}, @code{"xa"}, @code{"dnd"}, @code{"chat"}, @code{"error"} and @code{nil} (i.e. offline) @item status Presence status message for highest-priority connected resource @item resources Alist. Keys are strings (resource names), values are plists with properties @code{connected}, @code{show}, @code{status} and @code{priority}. @end table Incoming presence information is inserted in @code{resources}, and the information from the resource with the highest priority is inserted in @code{show} and @code{status} by the function @code{jabber-prioritize-resources}. @node Listening for new requests, Sending new requests, JID symbols, Hacking and extending @section Listening for new requests @findex jabber-send-iq @findex jabber-process-iq @findex jabber-signal-error @vindex jabber-iq-get-xmlns-alist @vindex jabber-iq-set-xmlns-alist To listen for new IQ requests, add the appropriate entry in @code{jabber-iq-get-xmlns-alist} or @code{jabber-iq-set-xmlns-alist}. The key is the namespace of the request, and the value is a function that takes two arguments, the connection object, and the entire IQ stanza in list format. @code{jabber-process-iq} reads these alists to determine which function to call on incoming packets. For example, the Ad-Hoc Commands module contains the following: @example (add-to-list 'jabber-iq-set-xmlns-alist (cons "http://jabber.org/protocol/commands" 'jabber-ahc-process)) @end example To send a response to an IQ request, use @samp{(jabber-send-iq @var{connection} @var{sender} "result" @var{query} nil nil nil nil @var{id})}, where @var{query} is the query in list format. @code{jabber-send-iq} will encapsulate the query in an IQ packet with the specified id. To return an error to the Jabber entity that sent the query, use @code{jabber-signal-error}. The signal is caught by @code{jabber-process-iq}, which takes care of sending the error. You can also use @code{jabber-send-iq-error}. @node Sending new requests, Extending service discovery, Listening for new requests, Hacking and extending @section Sending new requests @findex jabber-send-iq @findex jabber-process-iq To send an IQ request, use @code{jabber-send-iq}. It will generate an id, and create a mapping for it for use when the response comes. The syntax is: @example (jabber-send-iq @var{connection} @var{to} @var{type} @var{query} @var{success-callback} @var{success-closure} @var{failure-callback} @var{failure-closure}) @end example @var{success-callback} will be called if the response is of type @samp{result}, and @var{failure-callback} will be called if the response is of type @samp{error}. Both callbacks take three arguments, the connection object, the IQ stanza of the response, and the corresponding closure item earlier passed to @code{jabber-send-iq}. @findex jabber-report-success @findex jabber-process-data Two standard callbacks are provided. @code{jabber-report-success} takes a string as closure item, and reports success or failure in the echo area by appending either @samp{succeeded} or @samp{failed} to the string. @code{jabber-process-data} prepares a browse buffer. If its closure argument is a function, it calls that function with point in this browse buffer. If it's a string, it prints that string along with the error message in the IQ response. If it's anything else (e.g. @code{nil}), it just dumps the XML in the browse buffer. Examples follow. This is the hypothetical Jabber protocol ``frob'', for which only success report is needed: @example (jabber-send-iq connection "someone@@somewhere.org" "set" '(query ((xmlns . "frob"))) 'jabber-report-success "Frobbing" 'jabber-report-success "Frobbing") @end example This will print ``Frobbing succeeded'' or ``Frobbing failed: @var{reason}'', respectively, in the echo area. The protocol ``investigate'' needs to parse results and show them in a browse buffer: @example (jabber-send-iq connection "someone@@somewhere.org" "get" '(query ((xmlns . "investigate"))) 'jabber-process-data 'jabber-process-investigate 'jabber-process-data "Investigation failed") @end example Of course, the previous example could have used @code{jabber-report-success} for the error message. It's a matter of UI taste. @node Extending service discovery, Chat printers, Sending new requests, Hacking and extending @section Service discovery Service discovery (XEP-0030) is a Jabber protocol for communicating features supported by a certain entity, and items affiliated with an entity. jabber.el has APIs for both providing and requesting such information. @menu * Providing info:: * Requesting info:: @end menu @node Providing info, Requesting info, Extending service discovery, Extending service discovery @subsection Providing info Your new IQ request handlers will likely want to advertise their existence through service discovery. @vindex jabber-advertised-features To have an additional feature reported in response to disco info requests, add a string to @code{jabber-advertised-features}. @vindex jabber-disco-items-nodes @vindex jabber-disco-info-nodes By default, the service discovery functions reject all requests containing a node identifier with an ``Item not found'' error. To make them respond, add the appropriate entries to @code{jabber-disco-items-nodes} and @code{jabber-disco-info-nodes}. Both variables work in the same way. They are alists, where the keys are the node names, and the values are lists of two items. The first item is the data to return --- either a list, or a function taking the connection object and the entire IQ stanza and returning a list; in either case this list contains the XML nodes to include in the @code{} node in the response. @findex jabber-my-jid-p The second item is the access control function. An access control function receives the connection object and a JID as arguments, and returns non-nil if access is to be granted. If nil is specified instead of a function, access is always granted. One such function is provided, @code{jabber-my-jid-p}, which grants access for JIDs where the username and server (not necessarily resource) are equal to those of the user, or one of the user's configured accounts. @node Requesting info, , Providing info, Extending service discovery @subsection Requesting info jabber.el has a facility for requesting disco items and info. All positive responses are cached. To request disco items or info from an entity, user one of these functions: @defun jabber-disco-get-info jc jid node callback closure-data &optional force Get disco information for @var{jid} and @var{node}. A request is sent asynchronously on the connection @var{jc}. When the response arrives, @var{callback} is called with three arguments: @var{jc}, @var{closure-data}, and the result. The result may be retrieved from the cache, unless @var{force} is non-nil. If the request was successful, or retrieved from cache, it looks like @code{(@var{identities} @var{features})}, where @var{identities} and @var{features} are lists. Each identity is @code{["@var{name}" "@var{category}" "@var{type}"]}, and each feature is a string denoting the namespace of the feature. If the request failed, the result is an @code{} node. @end defun @defun jabber-disco-get-items jc jid node callback closure-data &optional force Get disco information for @var{jid} and @var{node}. A request is sent asynchronously on the connection @var{jc}. When the response arrives, @var{callback} is called with three arguments: @var{jc}, @var{closure-data}, and the result. The result may be retrieved from the cache, unless @var{force} is non-nil. If the request was successful, or retrieved from cache, the result is a list of items, where each item is @code{["@var{name}" "@var{jid}" "@var{node}"]}. The values are either strings or nil. If the request failed, the result is an @code{} node. @end defun If you only want to see what is in the cache, use one of the following functions. They don't use a callback, but return the result directly. @defun jabber-disco-get-info-immediately jid node Return cached disco information for @var{jid} and @var{node}, or nil if the cache doesn't contain this information. The result is the same as for @code{jabber-disco-get-info}. @end defun @defun jabber-disco-get-items-immediately jid node Return cached disco items for @var{jid} and @var{node}, or nil if the cache doesn't contain this information. The result is the same as for @code{jabber-disco-get-items}. @end defun In the future, this facility will be expanded to provide information acquired through XEP-0115, Entity capabilities, which is a protocol for sending disco information in @code{} stanzas. @node Chat printers, Stanza chains, Extending service discovery, Hacking and extending @section Chat printers @vindex jabber-chat-printers @vindex jabber-muc-printers @vindex jabber-body-printers @cindex Chat printers @cindex Body printers Chat printers are functions that print a certain aspect of an incoming message in a chat buffer. Included are functions for printing subjects (@code{jabber-chat-print-subject}), bodies (@code{jabber-chat-print-body}, and @code{jabber:x:oob}-style URLs (@code{jabber-chat-print-url}). The functions in @code{jabber-chat-printers} are called in order, with the entire @code{} stanza as argument. As described in the docstring of @code{jabber-chat-printers}, these functions are run in one of two modes: @code{printp}, in which they are supposed to return true if they would print anything, and @code{insert}, in which they are supposed to actually print something, if appropriate, using the function @code{insert}. For MUC, the functions in @code{jabber-muc-printers} are prepended to those in @code{jabber-chat-printers}. Body printers are a subgroup of chat printers. They are exclusive; only one of them applies to any given message. The idea is that ``higher-quality'' parts of the message override pieces included for backwards compatibility. Included are @code{jabber-muc-print-invite} and @code{jabber-chat-normal-body}; functions for XHTML-IM and PGP encrypted messages may be written in the future. The functions in @code{jabber-body-printers} are called in order until one of them returns non-nil. @node Stanza chains, , Chat printers, Hacking and extending @section Stanza chains @vindex jabber-message-chain @vindex jabber-iq-chain @vindex jabber-presence-chain If you really need to get under the skin of jabber.el, you can add functions to the lists @code{jabber-message-chain}, @code{jabber-iq-chain} and @code{jabber-presence-chain}. The functions in these lists will be called in order when an XML stanza of the corresponding type arrives, with the connection object and the entire XML stanza passed as arguments. Earlier functions can modify the stanza to change the behaviour of downstream functions, but remember: with great power comes great responsibility. @node Protocol support, Concept index, Hacking and extending, Top @appendix Protocol support @cindex Supported protocols These are the protocols currently supported (in full or partially) by jabber.el. @menu * RFC 3920:: XMPP-CORE * RFC 3921:: XMPP-IM * XEP-0004:: Data Forms * XEP-0012:: Last Activity * XEP-0020:: Feature Negotiation * XEP-0022:: Message Events * XEP-0030:: Service Discovery * XEP-0045:: Multi-User Chat * XEP-0049:: Private XML Storage * XEP-0050:: Ad-Hoc Commands * XEP-0054:: vcard-temp * XEP-0055:: Jabber Search * XEP-0065:: SOCKS5 Bytestreams * XEP-0066:: Out of Band Data * XEP-0068:: Field Standardization for Data Forms * XEP-0077:: In-Band Registration * XEP-0078:: Non-SASL Authentication * XEP-0082:: Jabber Date and Time Profiles * XEP-0085:: Chat State Notifications * XEP-0086:: Error Condition Mappings * XEP-0090:: Entity Time * XEP-0091:: Delayed Delivery * XEP-0092:: Software Version * XEP-0095:: Stream Initiation * XEP-0096:: File Transfer * XEP-0146:: Remote Controlling Clients * XEP-0153:: vCard-Based Avatars @end menu @node RFC 3920, RFC 3921, Protocol support, Protocol support @section RFC 3920 (XMPP-CORE) Most of RFC 3920 is supported, with the following exceptions. SASL is supported only when an external SASL library from FLIM or Gnus is present. As SASL is an essential part to XMPP, jabber.el will send pre-XMPP stream headers if it is not available. None of the stringprep profiles are implemented. jabber.el changes JIDs to lowercase internally; that's all. jabber.el doesn't interpret namespace prefixes. The @code{xml:lang} attribute is neither interpreted nor generated. SRV records are used if a modern version of @code{dns.el} is installed. @node RFC 3921, XEP-0004, RFC 3920, Protocol support @section RFC 3921 (XMPP-IM) Most of RFC 3921 is supported, with the following exceptions. Messages of type ``headline'' are not treated in any special way. The @code{} element is not used or generated. Sending ``directed presence'' is supported; however, presence stanzas received from contacts not in roster are ignored. Privacy lists are not supported at all. jabber.el doesn't support XMPP-E2E or ``im:'' CPIM URIs. @node XEP-0004, XEP-0012, RFC 3921, Protocol support @section XEP-0004 (Data Forms) XEP-0004 support is good enough for many purposes. Limitations are the following. Forms in incoming messages are not interpreted. See each specific protocol for whether forms are accepted in that context. ``Cancel'' messages are probably not consistently generated when they should be. This is partly a paradigm clash, as jabber.el doesn't use modal dialog boxes but buffers which can easily be buried. @code{} elements are not enforced. The field types ``jid-single'', ``jid-multi'' and ``list-multi'' are not implemented, due to programmer laziness. Let us know if you need them. @node XEP-0012, XEP-0020, XEP-0004, Protocol support @section XEP-0012 (Last Activity) jabber.el can generate all three query types described in the protocol. However, it does not answer to such requests. @node XEP-0020, XEP-0022, XEP-0012, Protocol support @section XEP-0020 (Feature Negotiation) There are no known limitations or bugs in XEP-0020 support. @node XEP-0022, XEP-0030, XEP-0020, Protocol support @section XEP-0022 (Message Events) jabber.el understands all four specified kinds of message events (offline, delivered, displayed, and composing) and by default requests all of them. It also reports those three events that make sense for clients. @node XEP-0030, XEP-0045, XEP-0022, Protocol support @section XEP-0030 (Service Discovery) Service discovery is supported, both as client and server. When used in the code, service discovery results are cached indefinitely. @node XEP-0045, XEP-0049, XEP-0030, Protocol support @section XEP-0045 (Multi-User Chat) jabber.el supports parts of XEP-0045. Entering, leaving and chatting work. So do invitations and private messages. Room configuration is supported. Changing roles of participants (basic moderation) is implemented, as is changing affiliations, but requesting affiliation lists is not yet supported. @node XEP-0049, XEP-0050, XEP-0045, Protocol support @section XEP-0049 (Private XML Storage) jabber.el contains an implementation of XEP-0049; however it is not used for anything right now. @node XEP-0050, XEP-0054, XEP-0049, Protocol support @section XEP-0050 (Ad-Hoc Commands) jabber.el is probably the first implementation of XEP-0050 (see @uref{http://article.gmane.org/gmane.network.jabber.devel/21413, post on jdev from 2004-03-10}). Both the client and server parts are supported. @node XEP-0054, XEP-0055, XEP-0050, Protocol support @section XEP-0054 (vcard-temp) Both displaying other users' vCards and editing your own vCard are supported. The implementation tries to follow the schema in the XEP accurately. @node XEP-0055, XEP-0065, XEP-0054, Protocol support @section XEP-0055 (Jabber Search) XEP-0055 is supported, both with traditional fields and with Data Forms (@pxref{XEP-0004}). As the traditional fields specified by the XEP is a subset of those allowed in XEP-0077, handling of those two form types are merged. @xref{XEP-0077}. @node XEP-0065, XEP-0066, XEP-0055, Protocol support @section XEP-0065 (SOCKS5 Bytestreams) XEP-0065 is supported. Currently jabber.el cannot act as a server, not even on on Emacsen that support server sockets (GNU Emacs 22 and up). Therefore it relies on proxies. Proxies have to be entered and queried manually. Psi's ``fast mode'' (@uref{http://delta.affinix.com/specs/stream.html}), which gives greater flexibility with regards to NAT, is not implemented. @node XEP-0066, XEP-0068, XEP-0065, Protocol support @section XEP-0066 (Out of Band Data) jabber.el will display URLs sent in message stanzas qualified by the @code{jabber:x:oob} namespace, as described in this XEP. Sending such URLs or doing anything with iq stanzas (using the @code{jabber:iq:oob} namespace) is not supported. @node XEP-0068, XEP-0077, XEP-0066, Protocol support @section XEP-0068 (Field Standardization for Data Forms) XEP-0068 is only used in the context of creating a new Jabber account, to prefill the username field of the registration form. @node XEP-0077, XEP-0078, XEP-0068, Protocol support @section XEP-0077 (In-Band Registration) In-band registration is supported for all purposes. That means registering a new Jabber account, changing Jabber password, removing a Jabber account, registering with a service, and cancelling registration to a service. Data forms are supported as well. URL redirections are not. jabber.el will not prevent or alert a user trying to change a password over an unencrypted connection. @node XEP-0078, XEP-0082, XEP-0077, Protocol support @section XEP-0078 (Non-SASL Authentication) Non-SASL authentication is supported, both plaintext and digest. Digest is preferred, and a warning is displayed to the user if only plaintext is available. @node XEP-0082, XEP-0085, XEP-0078, Protocol support @section XEP-0082 (Jabber Date and Time Profiles) The DateTime profile of XEP-0082 is supported. Currently this is only used for file transfer. @node XEP-0085, XEP-0086, XEP-0082, Protocol support @section XEP-0085 (Chat State Notifications) XEP-0085 is partially supported. Currently only active/composing notifications are @emph{sent} though all five notifications are handled on receipt. @node XEP-0086, XEP-0090, XEP-0085, Protocol support @section XEP-0086 (Error Condition Mappings) Legacy errors are interpreted, but never generated. XMPP style error messages take precedence when errors are reported to the user. @node XEP-0090, XEP-0091, XEP-0086, Protocol support @section XEP-0090 (Entity Time) jabber.el can query other entities for their time, and return the current time to those who ask. @node XEP-0091, XEP-0092, XEP-0090, Protocol support @section XEP-0091 (Delayed Delivery) The time specified on delayed incoming messages is interpreted, and displayed in chat buffers instead of the current time. @node XEP-0092, XEP-0095, XEP-0091, Protocol support @section XEP-0092 (Software Version) The user can request the version of any entity. jabber.el answers version requests to anyone, giving ``jabber.el'' as name, and the Emacs version as OS. @node XEP-0095, XEP-0096, XEP-0092, Protocol support @section XEP-0095 (Stream Initiation) XEP-0095 is supported, both incoming and outgoing, except that jabber.el doesn't check service discovery results before sending a stream initiation request. @node XEP-0096, XEP-0146, XEP-0095, Protocol support @section XEP-0096 (File Transfer) Both sending and receiving files is supported. If a suitable program is found, MD5 hashes of outgoing files are calculated and sent. However, hashes of received files are not checked. Ranged transfers are not supported. In-band bytestreams are not yet supported, even though XEP-0096 requires them. @node XEP-0146, XEP-0153, XEP-0096, Protocol support @section XEP-0146 (Remote Controlling Clients) The ``set-status'' command in XEP-0146 is supported. @node XEP-0153, , XEP-0146, Protocol support @section XEP-0153 (vCard-Based Avatars) vCard-based avatars are supported, both publishing and displaying. The pixel size limits on avatars are not enforced. @node Concept index, Function index, Protocol support, Top @unnumbered Concept index @printindex cp @node Function index, Variable index, Concept index, Top @unnumbered Function index @printindex fn @node Variable index, , Function index, Top @unnumbered Variable index @printindex vr @bye @ignore arch-tag: 995bf3da-0e87-4b15-895a-1e85fac139a2 @end ignore emacs-jabber-0.8.0/jabber-pkg.el.in0000644000175100017510000000024311133727374013717 00000000000000;; For ELPA: http://tromey.com/elpa/ (define-package "jabber" "@PACKAGE_VERSION@" "A Jabber client for Emacs.") ;; arch-tag: fa652136-12f7-11dd-b4c4-000a95c2fcd0 emacs-jabber-0.8.0/tests/0000777000175100017510000000000011252722242012202 500000000000000emacs-jabber-0.8.0/tests/load-all.el0000644000175100017510000000040211133727374014132 00000000000000;; Test that all files can be loaded (let* ((default-directory (expand-file-name (getenv "top_builddir"))) (elc-files (file-expand-wildcards "*.elc" t))) (dolist (f elc-files) (load f nil t))) ;; arch-tag: 509c4808-2e92-11dd-9c8c-000a95c2fcd0 emacs-jabber-0.8.0/tests/skip-tag-forward.el0000644000175100017510000000147711133727374015643 00000000000000;; Tests for jabber-xml-skip-tag-forward (require 'jabber-xml) (require 'cl) (flet ((parses-p (text) (with-temp-buffer (insert text) (goto-char (point-min)) (catch 'unfinished (jabber-xml-skip-tag-forward) (= (point) (point-max)))))) ;; 1. Just plain XML (unless (parses-p "ANONYMOUSDIGEST-MD5PLAIN") (error "Testcase 1 failed")) ;; 2. XML with CDATA (unless (parses-p "]]>") (error "Testcase 2 failed"))) ;; arch-tag: a99d8666-0e6b-11dd-bd33-000a95c2fcd0 emacs-jabber-0.8.0/tests/history.el0000644000175100017510000000324011133727374014151 00000000000000;; Tests for history (require 'jabber-history) ;; 1. Smoke test (let ((jabber-use-global-history t) (jabber-global-history-filename (make-temp-file "history-test")) ;; Jabber's birthday :) (our-time (encode-time 0 0 0 4 1 1999 0))) (unwind-protect (progn (jabber-history-log-message "in" "romeo@montague.net/Balcony" nil "hi" our-time) (with-temp-buffer (insert-file-contents-literally jabber-global-history-filename) (let ((expected "\\[\"\\([^\"]+\\)\" \"in\" \"romeo@montague.net/Balcony\" \"me\" \"hi\"]\n") (actual (buffer-string))) (unless (string-match expected actual) (error "Testcase 1 failed; %S doesn't match %S" actual expected)) ;; The timestamps don't match for some reason... ;; (let ((timestamp (match-string 1 actual))) ;; (unless (equal (jabber-parse-time timestamp) our-time) ;; (error "Testcase 1 failed; timestamp %S didn't match %S (%S vs %S)" timestamp (jabber-encode-time our-time) (jabber-parse-time timestamp) our-time))) ))) (delete-file jabber-global-history-filename))) ;; 2. Test with unwritable history file - should not signal an error ;; This should reflect out-of-disk condition too. (let ((jabber-use-global-history t) (jabber-global-history-filename (make-temp-file "history-test"))) (set-file-modes jabber-global-history-filename #o444) (unwind-protect (progn (jabber-history-log-message "in" "romeo@montague.net/Balcony" nil "hi" nil) (message "Please ignore the preceding \"Unable to write history\" error message.") ;; No error signalled - we're done. ) (delete-file jabber-global-history-filename))) ;; arch-tag: 43dd7ffe-22d7-11dd-9a7c-000a95c2fcd0 emacs-jabber-0.8.0/tests/jabberd.el0000644000175100017510000001140111133727374014037 00000000000000;;; Test the client by capturing its input and output into a virtual ;;; jabber server. This is not a test in itself, but a framework for ;;; actual tests. (require 'jabber) (require 'cl) (defvar jabberd-stanza-handlers '(jabberd-sasl jabberd-iq) "List of stanza handler hooks. These functions are called in order with two arguments, the client FSM and the stanza, until one function returns non-nil, indicating that it has handled the stanza.") (defvar jabberd-iq-get-handlers '(("jabber:iq:roster" . jabberd-iq-empty-success) ("jabber:iq:auth" . jabberd-iq-auth-get)) "Alist of handlers for IQ get stanzas. The key is the namespace of the request (a string), and the value is a function to handle the request. The function takes two arguments, the client FSM and the stanza.") (defvar jabberd-iq-set-handlers '(("urn:ietf:params:xml:ns:xmpp-bind" . jabberd-iq-bind) ("urn:ietf:params:xml:ns:xmpp-session" . jabberd-iq-empty-success) ("jabber:iq:auth" . jabberd-iq-empty-success)) "Alist of handlers for IQ set stanzas. The key is the namespace of the request (a string), and the value is a function to handle the request. The function takes two arguments, the client FSM and the stanza.") (defun jabberd-connect () (setq *jabber-virtual-server-function* #'jabberd-handle) (jabber-connect "romeo" "montague.net" nil nil "foo" nil nil 'virtual)) (defun jabberd-handle (fsm text) ;; First, parse stanzas from text into sexps. (let (stanzas) (with-temp-buffer (insert text) (goto-char (point-min)) ;; Skip processing directive (when (looking-at "<\\?xml[^?]*\\?>") (delete-region (match-beginning 0) (match-end 0))) (catch 'unfinished (while t (push (if (prog1 (looking-at ". (when (string-match "version=[\"']" stanza) (jabberd-send fsm '(stream:features () ;; Interesting implementation details ;; of jabber.el permit us to send all ;; features at once, without caring about ;; which step we are at. (mechanisms ((xmlns . "urn:ietf:params:xml:ns:xmpp-sasl")) (mechanism () "DIGEST-MD5")) (bind ((xmlns . "urn:ietf:params:xml:ns:xmpp-bind"))) (session ((xmlns . "urn:ietf:params:xml:ns:xmpp-session"))))))) (t (run-hook-with-args-until-success 'jabberd-stanza-handlers fsm stanza)))))) (defun jabberd-send (fsm stanza) (jabber-log-xml fsm "receive" stanza) (fsm-send fsm (list :stanza stanza))) (defun jabberd-sasl (fsm stanza) "Pretend to authenticate the client by SASL." (when (eq (jabber-xml-node-name stanza) 'auth) (jabberd-send fsm '(success ((xmlns . "urn:ietf:params:xml:ns:xmpp-sasl")))) t)) (defun jabberd-iq (fsm stanza) "Handle IQs from the client." (when (eq (jabber-xml-node-name stanza) 'iq) (jabber-xml-let-attributes (type id) stanza (cond ((member type '("get" "set")) (let* ((table (if (string= type "get") jabberd-iq-get-handlers jabberd-iq-set-handlers)) (ns (jabber-iq-xmlns stanza)) (function (cdr (assoc ns table)))) (when function (funcall function fsm stanza))))) t))) (defun jabberd-iq-empty-success (fsm stanza) "Send an empty IQ result to STANZA." (jabber-xml-let-attributes (id) stanza (jabberd-send fsm `(iq ((type . "result") (id . ,id)))))) (defun jabberd-iq-bind (fsm stanza) "Do resource binding for the virtual server." (let ((id (jabber-xml-get-attribute stanza 'id))) (jabberd-send fsm `(iq ((type . "result") (id . ,id)) (bind ((xmlns . "urn:ietf:params:xml:ns:xmpp-bind")) (jid () "romeo@montague.net/Orchard")))))) (defun jabberd-iq-auth-get (fsm stanza) (jabber-xml-let-attributes (id) stanza (jabberd-send fsm `(iq ((type . "result") (id . ,id)) (query ((xmlns . "jabber:iq:auth")) (username) (password) (digest) (resource)))))) (provide 'jabberd) emacs-jabber-0.8.0/tests/nick-change-fail.el0000644000175100017510000000602211133727374015531 00000000000000;;; When the user tries to change nickname in an MUC room, and the ;;; server denies this, we should detect this instead of believing ;;; that the user was thrown out of the room. (require 'jabberd) (defconst ncf-room-name "orchard@romeo-and-juliet.shakespeare.lit" "The MUC room used for this test.") (defun ncf-presence (fsm stanza) "Stanza handler. This function is a very simple MUC implementation. It allows a user to enter the room named by `ncf-room-name' with the nick \"Romeo\"." (jabber-xml-let-attributes (to) stanza (when (and (eq (jabber-xml-node-name stanza) 'presence) (string= (jabber-jid-user to) ncf-room-name)) (let ((nick (jabber-jid-resource to))) ;; Allow only the nick Romeo (if (string= nick "Romeo") (jabberd-send fsm `(presence ((from . ,to)) (x ((xmlns . "http://jabber.org/protocol/muc#user")) (item ((affiliation . "none") (role . "participant")))))) (jabberd-send fsm `(presence ((from . ,to) (type . "error")) (x ((xmlns . "http://jabber.org/protocol/muc#user"))) (error ((code . "409") (type . "cancel")) (conflict ((xmlns . "urn:ietf:params:xml:ns:xmpp-stanzas"))))))))))) (add-hook 'jabberd-stanza-handlers 'ncf-presence) (add-hook 'jabber-post-connect-hooks 'ncf-do) (setq jabber-muc-disable-disco-check t) (setq jabber-debug-log-xml t) (defvar ncf-done nil) ;; We need an extra variable for the error, as errors from timers are ;; ignored. (defvar ncf-error nil) (defun ncf-assert (assert-this format &rest args) (unless assert-this (let ((msg (apply #'format format args))) (setq ncf-error msg) (error "%s" msg)))) (defun ncf-do (jc) (setq ncf-done t) (jabber-groupchat-join jc ncf-room-name "Romeo") ;; We need a delay here, so that the client can process the response ;; stanza. (sit-for 0.01) (let ((buffer (jabber-muc-get-buffer ncf-room-name))) (ncf-assert (get-buffer buffer) "Couldn't enter MUC room") (ncf-assert *jabber-active-groupchats* "Entering room not recorded") ;; Now, do an unallowed nickname change. (jabber-groupchat-join jc ncf-room-name "Mercutio") (sit-for 0.01) ;; We should still consider ourselves to be in the room as Romeo (ncf-assert (assoc ncf-room-name *jabber-active-groupchats*) "We thought we left the room, but we didn't") (ncf-assert (string= (cdr (assoc ncf-room-name *jabber-active-groupchats*)) "Romeo") "We thought we changed nickname, but we didn't"))) (jabberd-connect) (with-timeout (5 (error "Timeout")) (while (not ncf-done) (sit-for 0.1))) (when ncf-error (princ (format "nick-change-fail test FAILED: %s " ncf-error)) (princ "Conversation was:\n") (with-current-buffer "*-jabber-xml-log-romeo@montague.net-*" (princ (buffer-string))) (let ((muc-buffer (get-buffer (jabber-muc-get-buffer ncf-room-name)))) (if muc-buffer (with-current-buffer muc-buffer (princ "Contents of groupchat buffer:\n") (princ (buffer-string))) (princ "Groupchat buffer not created.\n"))) (kill-emacs 1)) emacs-jabber-0.8.0/tests/Makefile.am0000644000175100017510000000034711133727374014167 00000000000000TESTS_ENVIRONMENT = env top_builddir=$(top_builddir) $(EMACS) -batch -L $(top_builddir) -L $(top_srcdir) -L $(srcdir) -l TESTS = load-all.el skip-tag-forward.el history.el jabberd.el nick-change-fail.el dist_noinst_DATA = $(TESTS) emacs-jabber-0.8.0/tests/Makefile.in0000644000175100017510000002421511252667712014201 00000000000000# Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = tests DIST_COMMON = $(dist_noinst_DATA) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/emacs-lib.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = DATA = $(dist_noinst_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EMACS = @EMACS@ EMACSLOADPATH = @EMACSLOADPATH@ GCONFTOOL = @GCONFTOOL@ GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@ GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ lispdir = @lispdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ TESTS_ENVIRONMENT = env top_builddir=$(top_builddir) $(EMACS) -batch -L $(top_builddir) -L $(top_srcdir) -L $(srcdir) -l TESTS = load-all.el skip-tag-forward.el history.el jabberd.el nick-change-fail.el dist_noinst_DATA = $(TESTS) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh tags: TAGS TAGS: ctags: CTAGS CTAGS: check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[ ]'; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *$$ws$$tst$$ws*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ echo "XPASS: $$tst"; \ ;; \ *) \ echo "PASS: $$tst"; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *$$ws$$tst$$ws*) \ xfail=`expr $$xfail + 1`; \ echo "XFAIL: $$tst"; \ ;; \ *) \ failed=`expr $$failed + 1`; \ echo "FAIL: $$tst"; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ echo "SKIP: $$tst"; \ fi; \ done; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="All $$all tests passed"; \ else \ banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all tests failed"; \ else \ banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ skipped="($$skip tests were not run)"; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ echo "$$dashes"; \ echo "$$banner"; \ test -z "$$skipped" || echo "$$skipped"; \ test -z "$$report" || echo "$$report"; \ echo "$$dashes"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(DATA) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-exec-am: install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-TESTS check-am clean clean-generic \ distclean distclean-generic distdir dvi dvi-am html html-am \ info info-am install install-am install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: emacs-jabber-0.8.0/gconf/0000777000175100017510000000000011252722242012134 500000000000000emacs-jabber-0.8.0/gconf/Makefile.am0000644000175100017510000000104011133727374014110 00000000000000schemadir = $(GCONF_SCHEMA_FILE_DIR) schema_DATA = emacs-jabber.schemas CLEANFILES = $(schema_DATA) EXTRA_DIST = emacs-jabber.schemas.in emacs-jabber.schemas: emacs-jabber.schemas.in Makefile sed -e "s|@""libexecdir@""|$(libexecdir)|" < $(srcdir)/emacs-jabber.schemas.in > emacs-jabber.schemas install-data-local: GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(schema_DATA) uninstall-local: GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-uninstall-rule $(schema_DATA) emacs-jabber-0.8.0/gconf/Makefile.in0000644000175100017510000002270211252667711014131 00000000000000# Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = gconf DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/emacs-lib.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = SOURCES = DIST_SOURCES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(schemadir)" schemaDATA_INSTALL = $(INSTALL_DATA) DATA = $(schema_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EMACS = @EMACS@ EMACSLOADPATH = @EMACSLOADPATH@ GCONFTOOL = @GCONFTOOL@ GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@ GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ lispdir = @lispdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ schemadir = $(GCONF_SCHEMA_FILE_DIR) schema_DATA = emacs-jabber.schemas CLEANFILES = $(schema_DATA) EXTRA_DIST = emacs-jabber.schemas.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gconf/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --foreign gconf/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-schemaDATA: $(schema_DATA) @$(NORMAL_INSTALL) test -z "$(schemadir)" || $(MKDIR_P) "$(DESTDIR)$(schemadir)" @list='$(schema_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(schemaDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(schemadir)/$$f'"; \ $(schemaDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(schemadir)/$$f"; \ done uninstall-schemaDATA: @$(NORMAL_UNINSTALL) @list='$(schema_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(schemadir)/$$f'"; \ rm -f "$(DESTDIR)$(schemadir)/$$f"; \ done tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(schemadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-data-local install-schemaDATA install-dvi: install-dvi-am install-exec-am: install-html: install-html-am install-info: install-info-am install-man: install-pdf: install-pdf-am install-ps: install-ps-am installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-local uninstall-schemaDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic distclean \ distclean-generic distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-data-local install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-schemaDATA install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am uninstall uninstall-am uninstall-local \ uninstall-schemaDATA emacs-jabber.schemas: emacs-jabber.schemas.in Makefile sed -e "s|@""libexecdir@""|$(libexecdir)|" < $(srcdir)/emacs-jabber.schemas.in > emacs-jabber.schemas install-data-local: GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(schema_DATA) uninstall-local: GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-uninstall-rule $(schema_DATA) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: emacs-jabber-0.8.0/gconf/emacs-jabber.schemas.in0000644000175100017510000000266711252704535016355 00000000000000 /schemas/desktop/gnome/url-handlers/xmpp/enabled /desktop/gnome/url-handlers/xmpp/enabled emacs-jabber bool true Whether the specified command should handle "xmpp" URLs True if the command specified in the "command" key should handle "xmpp" URLs. /schemas/desktop/gnome/url-handlers/xmpp/command /desktop/gnome/url-handlers/xmpp/command emacs-jabber string @libexecdir@/emacs-jabber-uri-handler "%s" The handler for "xmpp" URLs The command used to handle "xmpp" URLs, if enabled. /schemas/desktop/gnome/url-handlers/xmpp/needs_terminal /desktop/gnome/url-handlers/xmpp/needs_terminal emacs-jabber bool false Run the command in a terminal True if the command used to handle this type of URL should be run in a terminal. emacs-jabber-0.8.0/jabber.info0000644000175100017510000040251411252704757013077 00000000000000This is jabber.info, produced by makeinfo version 4.11 from jabber.texi. INFO-DIR-SECTION Emacs START-INFO-DIR-ENTRY * jabber.el: (jabber). Emacs Jabber client END-INFO-DIR-ENTRY This manual is for jabber.el, version 0.8. Copyright (C) 2004, 2005, 2006, 2007, 2008 Magnus Henoch, Tom Berger. Permission is granted to make and distribute verbatim copies or modified versions of this manual, provided the copyright notice and this permission notice are preserved on all copies.  File: jabber.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) jabber.el manual **************** This manual is for jabber.el, version 0.8. Copyright (C) 2004, 2005, 2006, 2007, 2008 Magnus Henoch, Tom Berger. Permission is granted to make and distribute verbatim copies or modified versions of this manual, provided the copyright notice and this permission notice are preserved on all copies. * Menu: * Introduction:: * Basic operation:: * Groupchat:: * Composing messages:: * File transfer:: * Services:: * Personal information:: * Avatars:: * Time queries:: * Useful features:: * Message history:: * Typing notifications:: * Roster import and export:: * XMPP URIs:: * Customization:: * Hacking and extending:: * Protocol support:: * Concept index:: * Function index:: * Variable index::  File: jabber.info, Node: Introduction, Next: Basic operation, Prev: Top, Up: Top 1 Introduction ************** jabber.el is a Jabber client running under Emacs. For more information on the open-protocol instant messaging network Jabber, please visit `http://www.jabber.org'. As a Jabber client, jabber.el is mostly just a face in the crowd, except that it uses buffers where GUI clients have windows. There is a roster buffer, and to chat with someone you open a chat buffer, and there are buffers for interaction with servers and services. Then again, jabber.el delivers excellent console performance and customizable hooks (if you have speech synthesizer software, hook it up to your presence alerts). jabber.el does not yet support PGP encryption, sending and receiving roster items, and various other things. * Menu: * Contact::  File: jabber.info, Node: Contact, Prev: Introduction, Up: Introduction 1.1 Contact =========== * There is a web page at `http://emacs-jabber.sf.net/'. * There is a Sourceforge project page at `http://sourceforge.net/projects/emacs-jabber', with bug and patch trackers. * There is a mailing list: , `https://lists.sourceforge.net/lists/listinfo/emacs-jabber-general', `http://dir.gmane.org/gmane.emacs.jabber.general' * There is a chat room, `jabber.el@conference.jabber.se'. If you have successfully connected, you can join it by typing `M-x jabber-groupchat-join' and entering the address.  File: jabber.info, Node: Basic operation, Next: Groupchat, Prev: Introduction, Up: Top 2 Basic operation ***************** This chapter is intended as an introduction to basic usage of jabber.el. If you have used Jabber before and are familiar with the terminology, you might find it a bit too basic--in that case, just skim it, making sure to pick up the commands mentioned. I'll assume that you have already successfully installed jabber.el; if not, consult the `README' file. Also, make sure you have `(require 'jabber)' or `(load "jabber-autoloads")' in your `.emacs'. There are a handful of global keybindings for common commands. They start with `C-x C-j', and you can get a list of them by typing `C-x C-j C-h'. * Menu: * Do you have a Jabber account?:: * Registering an account:: * Connecting:: * Chatting:: * Presence:: * Presence subscription:: * Roster buffer::  File: jabber.info, Node: Do you have a Jabber account?, Next: Registering an account, Prev: Basic operation, Up: Basic operation 2.1 Do you have a Jabber account? ================================= Jabber has become rather popular as an instant messaging technology. Several sites use it, but often not under the names "Jabber" or "XMPP". Examples: * Google Talk uses Jabber. If you have a Gmail address, you can use it as a Jabber ID. *Note Account settings::, for Google-specific configuration. * LJ Talk (of Livejournal) uses Jabber. Your Jabber ID is `LJUSERNAME@livejournal.com'.  File: jabber.info, Node: Registering an account, Next: Connecting, Prev: Do you have a Jabber account?, Up: Basic operation 2.2 Registering an account ========================== If you do not yet have a Jabber account, you can register one. The registration processes for various servers differ, but many servers support so-called "in-band registration", which is described in this section. To register an account, type `C-u M-x jabber-connect' and enter your desired JID in the form `USERNAME@SERVER'. You will be presented with a registration form to fill out and send. There the username you chose will be prefilled. After registration, you can connect to the server as usual.  File: jabber.info, Node: Connecting, Next: Chatting, Prev: Registering an account, Up: Basic operation 2.3 Connecting ============== Now, type `C-x C-j C-c' and enter your JID and password. If you successfully connect, jabber.el will download your roster and display it in a buffer called `*-jabber-roster-*'. By default, you will appear as "online" to your contacts. To change this to e.g. "away", type `M-x jabber-send-presence' or `C-x C-j C-p'. *Note Presence::, for more information. To disconnect, type `M-x jabber-disconnect' or `C-x C-j C-d'. Use `M-x jabber-disconnect-one' to disconnect just one account (or just type `C-u C-x C-j C-d'). If you don't want to type your JID every time you connect, you can save it in the variable `jabber-account-list'. *Note Account settings::. If you configure more than one account, all of them will be connected when you type `C-x C-j C-c', as that key is bound to `jabber-connect-all'. To connect only one account, possibly one that's not in your list, type `M-x jabber-connect' or `C-u C-x C-j C-c'.  File: jabber.info, Node: Chatting, Next: Presence, Prev: Connecting, Up: Basic operation 2.4 Chatting ============ There are several ways to open a chat buffer. The shortest way is to put point over the person you want to chat with in the roster display and hit RET. You can also use the function `jabber-chat-with'. This function is bound to `C-x C-j C-j' in the global keymap. You will be asked to enter a JID in the minibuffer. You can also enter the roster name of one of your contacts. All JIDs and names in your roster can be tab-completed. You can also use menus to access commands. In the roster display, you can access several menus through keystrokes or mouse clicks. You can bring one big menu up by pressing the second mouse button, or you can bring up the "chat menu" by typing `C-c C-c'. If you do the latter while point is on a roster entry, that entry will be the default value when you are asked for whom to chat with. Now, try opening a chat with someone. A buffer named `*-jabber-chat-:-PERSON-*' will be created and selected. Type your message at the end of the buffer, and hit `RET' to send it. To include a newline in your message, use `C-j'. When you receive a message from someone, you will see a red indicator in the mode line. You can click this indicator with the mouse, or type `C-x C-j C-l' to switch to the relevant buffer. *Note Tracking activity::.  File: jabber.info, Node: Presence, Next: Presence subscription, Prev: Chatting, Up: Basic operation 2.5 Presence ============ "Presence" is the Jabber term for letting other people know that you are online, and additionally how "available" you are. There are three elements to presence: availability state (called "show"), status message, and priority. Your show state may either be empty (meaning simply "online"), or one of `away', `xa', `dnd' and `chat', meaning "away", "extended away" (i.e. away for an extended period), "do not disturb", and "free for chat", respectively. This information is available to everyone subscribing to your presence, but technically it does not restrict anyone's actions. You can chat with people even if you claim to be away. The status message is a short text complementing your show status, such as "at home", "working", "phone", "playing games" or whatever you want. It is sent to everyone subscribing to your presence, but not all clients prominently display it to the user. The priority is only interesting if you are running more than one Jabber client at a time accessing the same account. *Note Resources and priority::. To set your presence, use the function `jabber-send-presence' (bound to `C-x C-j C-p'). It can be called both interactively and in Lisp code. For the latter case, use something like `(jabber-send-presence "away" "idle for 10 minutes" 10)'. There are a few shortcuts: `C-x C-j C-a' Send "away" presence (with prefix argument, specify status text) `C-x C-j C-x' Send "extended away" presence (with prefix argument, specify status text) `C-x C-j C-o' Send default presence (see below) By default, jabber.el sets your presence when you connect. If you want it not to do that, remove `jabber-send-current-presence' from `jabber-post-connect-hooks'. If you want to change the presence that is sent, change the variables `jabber-default-show', `jabber-default-status' and `jabber-default-priority'. With jabber.el, you can set your presence remotely. *Note Ad-Hoc Commands::. * Menu: * Resources and priority:: * Directed presence::  File: jabber.info, Node: Resources and priority, Next: Directed presence, Prev: Presence, Up: Presence 2.5.1 Resources and priority ---------------------------- Every connection to an account has a specific name, a "resource". The account itself has a JID of the form `USERNAME@SERVER' (a "bare JID"), but the connections have JIDs of the form `USERNAME@SERVER/RESOURCE' (a "full JID"). You can choose the resource name yourself by entering a JID of the latter form at the connection prompt (*note Connecting::), or by configuring it in `jabber-account-list' (*note Account settings::) Each session has a "priority". The priority determines what happens when a message is sent to the bare JID (i.e. without specifying what connection should receive message). Such messages are delivered to the connection with the highest non-negative priority value. If there are no connections, or if all connections have negative priority, the message is either stored on the server for later delivery or bounced to the sender, depending on the server configuration. If there are several connections with the same priority, the behaviour depends on the server. Some server implementations deliver the message to all such connections, while others choose one connection depending on certain rules. Note that these rules do not apply when a message is sent to a full JID. Such messages are sent to the specified resource, if it is still connected, and otherwise treated as messages to the bare JID. In the chat buffers of jabber.el, messages are sent to whatever JID the last message came from (usually a full JID), or to the bare JID if no message has been received yet. Other clients may have different behaviour.  File: jabber.info, Node: Directed presence, Prev: Resources and priority, Up: Presence 2.5.2 Directed presence ----------------------- You can send "directed presence" with `M-x jabber-send-directed-presence'. This is mostly useful to manage transports--sending directed presence is a way to turn them on and off. You can also send directed presence to an annoying contact to appear as away or offline to that contact. Note, however, that in both of these cases, all subscribed entities will get your next global presence update.  File: jabber.info, Node: Presence subscription, Next: Roster buffer, Prev: Presence, Up: Basic operation 2.6 Presence subscription ========================= Having permission to view the presence status of a person is called "subscribing to his presence". Presence subscription between two persons can be asymmetric. Subscription state is shown in the roster display by arrows (*note Customizing the roster buffer::). A left-pointing arrow means that the contact can see your presence ("from"). A right-pointing arrow means that you can see the contact's presence ("to"). The most common case is mutual subscription, a double-ended arrow ("both"). When jabber.el receives a presence subscription request, it will present it to you in a chat buffer, and offer you to choose subscription mode and send a subscription request back to that person. The "Mutual" button accepts the request and sends a reciprocal request.(1) The "One-way" button accepts the request, but doesn't ask for a subscription in return. The "Decline" button declines the request. To request subscription to someone, type `M-x jabber-send-subscription-request'. You will be prompted for the JID to send it to. This command can also be accessed through the Roster menu, by typing `C-c C-r' in the roster buffer. After that, you will probably want to give the contact a more readable name. The command for that is `jabber-roster-change', which is also available in the Roster menu or by typing `e' on a person in the roster buffer. ---------- Footnotes ---------- (1) If this request is superfluous, the server will drop it without bothering the contact.  File: jabber.info, Node: Roster buffer, Prev: Presence subscription, Up: Basic operation 2.7 The roster buffer ===================== The roster buffer is called `*-jabber-roster-*'. It simply contains a list of the contacts on your roster. If you have several accounts connected, contacts will be grouped by account. In the roster buffer, any command which requires a JID will default to the JID under point when called. These commands can be called through either keyboard menus or mouse menus. To open a menu with the mouse, simply press the second mouse button over the JID in question.(1) This will bring up a menu with all available actions. The keyboard menus are split into categories: Chat, Roster, Information, MUC (Multi-User Chat, or groupchat) and Services, opened by `C-c C-c', `C-c C-r', `C-c C-i', `C-c C-m' and `C-c C-s', respectively. A list of keybindings is displayed at the top of the roster buffer. You can turn it off by setting `jabber-roster-show-bindings' to nil. You can call `jabber-display-roster' (bound to `g') to redisplay your roster according to changed preferences (*note Customizing the roster buffer::). This will not refetch your roster from the server. Refetching the roster is usually not needed, since updates are pushed to clients automatically. You can choose not to have the roster updated automatically on presence changes (*note Presence alerts::). In that case, you need to call `jabber-display-roster' manually. Please note, that by default offline contacts showed in roster as any others. To hide them, you can use `o' in roster buffer. To permanently hide them, customize `jabber-show-offline-contacts' variable. ---------- Footnotes ---------- (1) For some reason, mouse menus don't work in XEmacs. Patches are welcome.  File: jabber.info, Node: Groupchat, Next: Composing messages, Prev: Basic operation, Up: Top 3 Groupchat *********** The groupchat menu can be accessed by typing `C-c C-m' in the roster buffer. You can also type the commands directly, as will be shown here. To join a groupchat, type `M-x jabber-groupchat-join'. You will be prompted for the groupchat to join, and your nickname in the groupchat. This nickname doesn't need to have any correlation to your JID; in fact, groupchats are usually (but not always) configured such that only moderators can see your JID. You can change your nickname with `M-x jabber-muc-nick'. *Note Configuration::, for setting default nicknames. When trying to join a room, jabber.el first sends a service discovery info request to the room, to find out whether it exists and what features are enabled (in particular whether the room is password-protected). However, this can cause problems with some buggy MUC services (or services that respond in a way that jabber.el doesn't expect). A workaround for that is to set `jabber-muc-disable-disco-check' to `t'; however, the bug should be unearthed and fixed. Groupchat messages will be displayed in a buffer called `*-jabber-groupchat-:-GROUPCHAT-*'. By default, the buffer name is based on the JID of the chat room. If you want a shorter name, you can add the chat room to your roster and give it a name, using the command `M-x jabber-roster-change'. The groupchat buffer works much like the chat buffer. It has its own class of alerts (*note Customizing alerts::), and uses activity tracking (*note Tracking activity::). Also, to save from repeating unnesesary typing you can press `Tab' key to complete nick of a groupchat member that you are talking with. You can customize your form of personal talking in MUC (`jabber-muc-completion-delimiter') and form of personal talking to you (`jabber-muc-looks-personaling-symbols')--see "jabber-chat" customization group. Defaults are sane, so it is unlikely that you would want to change this, but... it is Emacs! To change the topic of a groupchat, type `M-x jabber-muc-set-topic'. The current topic is shown in the header line. To leave a groupchat, type `M-x jabber-groupchat-leave'. If you are the owner of a groupchat, you can change its configuration by typing `M-x jabber-groupchat-get-config'. A configuration form will be rendered in new buffer. To see which people are in a groupchat, type `M-x jabber-muc-names'. This gives a list of nicknames, "roles", "affiliations", and possibly JIDs. *Note MUC Administration::, for the meaning of roles and affiliations. * Menu: * Configuration:: * Invitations:: * Private messages:: * MUC Administration::  File: jabber.info, Node: Configuration, Next: Invitations, Prev: Groupchat, Up: Groupchat 3.1 Configuration ================= You can configure jabber.el to use a certain nickname for a certain room, or to automatically join a certain room when you connect. You can do this either by storing bookmarks on the server or by setting Emacs variables. Type `M-x jabber-edit-bookmarks' to add bookmarks. You can specify the JID of the conference, the name of the conference (not used by jabber.el), whether to automatically join the room, your desired nickname (or leave empty), and the room password (or leave empty). The default nickname for groupchats is the username part of your JID. If you don't use bookmarks, you can set different nicknames for different groups by customizing `jabber-muc-default-nicknames'. There you specify the JID of the group, and your preferred nickname. Automatically joining certain rooms when connecting can be accomplished by setting `jabber-muc-autojoin' to a list containing the JIDs of the rooms you want to enter. To disable this feature, remove `jabber-muc-autojoin' from `jabber-post-connect-hooks'. Please note, that `jabber-muc-default-nicknames' and `jabber-muc-autojoin' are machine-local, but apply to _all_ accounts--if you connect several accounts, both will try to connect to the same chat rooms, or use the same nickname. This will lead to confusion.  File: jabber.info, Node: Invitations, Next: Private messages, Prev: Configuration, Up: Groupchat 3.2 Invitations =============== You can invite someone to a groupchat with `M-x jabber-muc-invite' (also available in the MUC menu). Pay attention to the order of the arguments--as both users and rooms are just JIDs, it is technically possible to invite a room to a user, but that's probably not what you want. When you receive an invitation, it appears in the chat buffer along with two buttons, "Accept" and "Decline". Pressing "Accept" enters the room, as you would expect. Pressing "Decline" gives you an opportunity to state the reason why you're not joining.  File: jabber.info, Node: Private messages, Next: MUC Administration, Prev: Invitations, Up: Groupchat 3.3 Private messages ==================== You can open a private chat with a participant in a chat room with `M-x jabber-muc-private' (or by using the MUC menu). This creates a buffer with the name `*-jabber-muc-priv-GROUP-NICKNAME-*' (customizable by `jabber-muc-private-buffer-format'), which behaves mostly like an ordinary chat buffer. This buffer will also be created if someone sends a private message to you. Private MUC messages use the same alerts as normal chat messages. *Note Message alerts::.  File: jabber.info, Node: MUC Administration, Prev: Private messages, Up: Groupchat 3.4 Administration ================== Administration of a MUC room mostly consists of managing roles and affiliations. Roles are temporary, and apply until the user leaves the room. Affiliations are permanent, and based on JIDs. 3.4.1 Roles ----------- If you have moderator privileges, you can change the role of a participant with `M-x jabber-muc-set-role'. Kicking means setting the role to "none". Granting and revoking voice are "participant" and "visitor", respectively. "moderator" gives moderator privileges, obviously. The possible roles are: `moderator' Has voice, can change other people's roles. `participant' Has voice. `visitor' Doesn't have voice (can't send messages to everyone, but can send private messages) `none' Not in room. 3.4.2 Affiliations ------------------ If you have admin or owner privileges, you can change the affiliation of a user with `M-x jabber-muc-set-affiliation'. Affiliation is persistent, and based on JIDs. Depending of your affiliation and the MUC implementation, you might not be allowed to perform all kinds of changes, and maybe not in one step. Affiliations are: `owner' Can destroy room, appoint admins, make people members, ban people. `admin' Can make people members or ban people. `member' Can enter the room, and has voice by default. `none' Rights depend on room configuration. The room might be members-only, or grant voice only to members. `outcast' Banned from the room.  File: jabber.info, Node: Composing messages, Next: File transfer, Prev: Groupchat, Up: Top 4 Composing messages ******************** The chat buffer interface can be inconvenient for some purposes. As you can't use `RET' to insert a newline (use `C-j' for that), writing a longer message can be painful. Also, it is not possible to include a subject in the message, or send the message to multiple recipients. These features are implemented by the message composing tool. Type `M-x jabber-compose' to start it. In the buffer that comes up, you can specify recipients, enter a subject, and type your message.  File: jabber.info, Node: File transfer, Next: Services, Prev: Composing messages, Up: Top 5 File transfer *************** jabber.el has limited support for file transfer. The most important limit is that files sent and received are kept in buffers, so Emacs must be able to allocate enough memory for the entire file, and the file size must be smaller than the maximum buffer size.(1) jabber.el is able to exchange files with most Jabber clients (and also some MSN transports), but notably not with the official Google Talk client. The Google Talk client uses a different file transfer protocol which, at the time of this release, has not been published. * Menu: * Receiving files:: * Sending files:: ---------- Footnotes ---------- (1) The maximum buffer size depends on in the variable `most-positive-fixnum'. On 32-bit systems, this is 128 or 256 megabytes, depending on your Emacs version.  File: jabber.info, Node: Receiving files, Next: Sending files, Prev: File transfer, Up: File transfer 5.1 Receiving files =================== Receiving files requires no configuration. When someone wants to send a file to you, you are asked (through `yes-or-no-p') whether you want to accept the file. If you answer yes, you get to choose where to save the file. If the sender's client is correctly configured (this is often not the case; see below), the file transfer will start. Currently, the only way to watch the progress is to inspect the buffer of the file being transfered; `C-x C-b' is one way of doing that. *Note Listing Existing Buffers: (emacs)List Buffers. When the transfer is done, the message "FILE downloaded" appears in the echo area, and the buffer is killed. If this doesn't happen, it is most likely the sender's fault. The sender needs to have a public IP address, either directly, through port forwarding (in which case the client needs to be configured with the real public IP address), or through an XEP-0065 proxy. If you have activated XML logging (*note Debug options::), you can see the IP address that the other client is asking you to connect to there. Often you will find that this is an internal IP address (often starts with `192.168'). See the documentation of the sender's client for setting this up.  File: jabber.info, Node: Sending files, Prev: Receiving files, Up: File transfer 5.2 Sending files ================= To send a file to someone, you need an XEP-0065 proxy.(1) If your Jabber server hosts such a proxy, it will be found automatically, otherwise it needs to be manually configured. You can check whether your Jabber server has a proxy with `M-x jabber-get-disco-items'; see *note Service discovery::. To configure a proxy manually, customize the variable `jabber-socks5-proxies'. Putting `proxy.jabber.se' there should work. Type `M-x jabber-socks5-query-all-proxies' to see if the proxies answer. Now, you can type `M-x jabber-ft-send' to send a file to someone. You need to enter the correct full JID, including resource, to get this right. If the contact is logged in with only one client, and you can see it online, just typing the JID or roster name is enough. If you run the command from a chat buffer, the JID of the contact is given as the default value. If the contact has several clients online, you probably want to send the file to a particular one. If you run this command from within a chat buffer, the default target will be the one that last sent a message to you. If you just type a bare JID or a roster name, the client with the highest priority will get the file. If the contact accepts the file, and the contact's client succeeds in connecting to the proxy, jabber.el will send the file through the proxy. During this time, your Emacs will be blocked, so you might want to avoid sending large files over slow connections. ---------- Footnotes ---------- (1) This requirement is not inherent in the protocol, only in the current file transfer implementation of jabber.el, and in Emacs versions earlier than 22.  File: jabber.info, Node: Services, Next: Personal information, Prev: File transfer, Up: Top 6 Services ********** Not every Jabber entity is a physical person. There are many automatic entities, called servers, services, components, agents, transports and other names. The use of these is described here. The functions described in this chapter use "browse buffers". Browse buffers are named `*-jabber-browse-:-SERVICE-*', sometimes with a numerical suffix. The different menus have the same keybindings as in the roster buffer, and if you call a function operating on a JID while point is over a JID, that JID will be the default value, so you don't have to type it or copy it yourself. You can change the buffer name template by customizing the variable `jabber-browse-buffer-format'. * Menu: * Commands:: * Your home server:: * Transports:: * User directories:: * MUC services::  File: jabber.info, Node: Commands, Next: Your home server, Prev: Services, Up: Services 6.1 Commands ============ A small number of commands is used for almost all interaction with Jabber services. Essentially, they are all the same: you request a form from the server, fill it in, and send it back. Most of these commands are available under the Service menu, which is opened by typing `C-c C-s'. Service discovery is under the Info menu instead, which is available under `C-c C-i'. * Menu: * Registration:: * Search:: * Ad-Hoc Commands:: * Service discovery:: * Browsing::  File: jabber.info, Node: Registration, Next: Search, Prev: Commands, Up: Commands 6.1.1 Registration ------------------ You can get a registration form for a service by typing `M-x jabber-get-register' and entering the JID of the service. On success, you get a single-stage form to fill in. There are two buttons at the bottom of the form, "Submit" and "Cancel registration". "Submit" does what you would expect it to, but "Cancel registration" cancels any existing registration with the service. Whichever of them you choose, you get a message in the echo area informing whether the operation succeeded.  File: jabber.info, Node: Search, Next: Ad-Hoc Commands, Prev: Registration, Up: Commands 6.1.2 Search ------------ You can get a search form for a service by typing `M-x jabber-get-search'. This gives you a single-stage form to fill in. After you press the "Submit" button at the bottom, the search results will be displayed in the same buffer. * Menu: * Ad-Hoc Commands::  File: jabber.info, Node: Ad-Hoc Commands, Next: Service discovery, Prev: Search, Up: Commands 6.1.3 Ad-Hoc Commands --------------------- jabber.el supports a subset of XEP-0050, the standard for Ad-Hoc Commands. As the name implies, this can be used for just about anything. In particular, it is used not only by services, but also by clients (e.g. Psi, and jabber.el itself). To find which commands are available, run "Request command list" (`jabber-ahc-get-list').(1) To run a command from the list, put point over it and run "Execute command" (`jabber-ahc-execute-command'), accepting the defaults for JID and node. (If you already know those, you could of course enter them yourself.) What happens next depends on the command and the service. In some cases, the service just responds that the command has been run. You may also get a form to fill out. This form may have multiple stages, in which case there are "Next" and "Previous" buttons for navigating between stages. You may also see "Complete", which runs the command skipping any remaining stages of the form, and "Cancel", which cancels the command. Currently, jabber.el uses ad-hoc commands for setting presence remotely. If you realize that you forgot to set your client to "away" with a low priority, you can do it remotely from any JID from `jabber-account-list'. So, you can add disabled JIDs in `jabber-account-list' to allow them control your presence.(2) ---------- Footnotes ---------- (1) This is the same thing as a disco items request to the node `http://jabber.org/protocol/commands'. (2) Most Jabber servers also support kicking a client off the net by logging in with another client with exactly the same resource.  File: jabber.info, Node: Service discovery, Next: Browsing, Prev: Ad-Hoc Commands, Up: Commands 6.1.4 Service discovery ----------------------- Service discovery is used to find information about servers, services and clients. There are two kinds of requests: find "info" about a Jabber entity--i.e. its identity and supported features--and find "items" related to an entity, where the definition of "related" is left to the entity itself. The commands to execute such requests are `jabber-get-disco-info' and `jabber-get-disco-items', respectively. These commands can be accessed from the Info menu, which is opened by typing `C-c C-i'. The commands accept a JID and optionally a "node". The result of such a command is displayed in a browse buffer. For an info request, the result just lists the identities and features of the entity. For an item request, the related items are listed. The items may be JIDs, or JIDs with a node. If you put point on one of the items, its JID and node will be the default value for any Jabber command. If you think that the interface to service discovery is awkward and should be replaced with something better, you are completely right.  File: jabber.info, Node: Browsing, Prev: Service discovery, Up: Commands 6.1.5 Browsing -------------- Before service discovery, browsing was the way to find information about Jabber entities. Nowadays it is all but superseded, but jabber.el still supports it. You can use it by typing `M-x jabber-get-browse'. It works much like service discovery.  File: jabber.info, Node: Your home server, Next: Transports, Prev: Commands, Up: Services 6.2 Your home server ==================== You can interact with your Jabber server to change your password or remove your account. Both of these can be accomplished by typing `M-x jabber-get-register' and typing the JID of your server; *note Registration::.  File: jabber.info, Node: Transports, Next: User directories, Prev: Your home server, Up: Services 6.3 Transports to other IM networks =================================== Some Jabber services make it possible to communicate with users on other instant messaging networks (e.g. MSN, ICQ, AIM), in effect turning your Jabber client into a multi-protocol client. These are called "gateways" or "transports". They work by impersonating you on the legacy network; therefore you need to provide your username and password through registration. 6.3.1 Finding a transport ------------------------- To use such a transport, you first need to find one, obviously. Sometimes your home server provides the transports you need, but you are not limited to those; in principle you can use any transport on the Jabber network. Some transports only accept local users, though. Transports are generally mentioned on the web page of the Jabber server in question. You can also find transports from within the client; *note Service discovery::. 6.3.2 Registering with a transport ---------------------------------- To register with a transport, type `M-x jabber-get-register' and enter the JID of the transport. This will open a registration form where you get to fill in your login information; *note Registration::. You can later use this same form to change the information or cancel your registration. After you have registered, the transport will request presence subscription. It needs that to know when you are online, and synchronize your presence on the legacy network. 6.3.3 Contact list ------------------ Once you are registered, the transport will transfer the contact list from the legacy service. From the Jabber side, it appears as if lots of people suddenly request presence subscription to you. This is somewhat inconvenient, but it is currently the only way that the transport can influence your Jabber contact list, as it is an entity external to your server.(1) When you have accepted these presence subscriptions, the contacts from legacy networks appear as if they were Jabber contacts. 6.3.4 Finding users ------------------- Some legacy networks have a global database of users, and some transports support searching that database. In that case, you can search for other users with `M-x jabber-get-search'; *note Search::. ---------- Footnotes ---------- (1) Of course, jabber.el could do more to alleviate this inconvenience.  File: jabber.info, Node: User directories, Next: MUC services, Prev: Transports, Up: Services 6.4 User directories ==================== There are some Jabber user directories, usually abbreviated JUDs. The most well-known one is `users.jabber.org'. You can register with such a directory to let other people find you (*note Registration::), and you can search the directory (*note Search::).  File: jabber.info, Node: MUC services, Prev: User directories, Up: Services 6.5 MUC services ================ MUC services (Multi-User Chat, chat rooms) are usually not operated by these commands, but by commands specific to the MUC protocol; *note Groupchat::. However, some MUC services offer nickname registration through the registration protocol (*note Registration::), and other commands; *note Ad-Hoc Commands::.  File: jabber.info, Node: Personal information, Next: Avatars, Prev: Services, Up: Top 7 Personal information ********************** The Jabber way of handling personal information (name, addresses, phone numbers, etc) is "vCards" encoded in XML.(1) You can get information about a user by running `M-x jabber-vcard-get', and you can edit your own information by running `M-x jabber-vcard-edit'. The form for editing your information can be slightly confusing--you are allowed to enter any number of addresses, phone numbers and e-mail addresses, each of which has a set of orthogonal properties. You can add and remove items with the `[INS]' and `[DEL]' buttons, respectively. This is also where you set your avatar (*note Avatars::). The size of your avatar file is limited to 8 kilobytes. ---------- Footnotes ---------- (1) *Note XEP-0054::.  File: jabber.info, Node: Avatars, Next: Time queries, Prev: Personal information, Up: Top 8 Avatars ********* jabber.el supports viewing and publishing avatars according to XEP-0153, vCard-Based Avatars. By default, if you have an avatar in your vCard (*note Personal information::), it will be published for others to see, and if other people publish their avatars, they will be displayed in the roster buffer and in the header line of chat buffers, if your Emacs can display images. Otherwise, jabber.el will not fetch avatars at all. To disable retrieval of other people's avatars, set `jabber-vcard-avatars-retrieve' to nil. To disable publishing of your own avatar, set `jabber-vcard-avatars-publish' to nil. To disable avatars in chat buffer header lines, set `jabber-chat-buffer-show-avatar' to nil. There are a number of restrictions on avatar images in the specification. Most of them are not enforced by jabber.el. * The image should be smaller than 8 kilobytes; this is enforced by jabber.el. * The image height and width should be between 32 and 96 pixels; the recommended size is 64 by 64 pixels. * The image should be square. * The image should be in either PNG, GIF, or JPEG format. (jabber.el will behave incorrectly if the image is not in a format supported by Emacs.) Avatars are cached in the directory specified by `jabber-avatar-cache-directory', by default `~/.jabber-avatars/'. The cache is never cleaned, so you might want to do that yourself from time to time.  File: jabber.info, Node: Time queries, Next: Useful features, Prev: Avatars, Up: Top 9 Time queries ************** With `M-x jabber-get-time', you can ask what time an entity (client, server or component) thinks it is, and what time zone it thinks it is in. You can query a server about when a certain user was last seen online. Use `M-x jabber-get-last-online' for that. You can also ask a client about how long a user has been idle with `M-x jabber-get-idle-time'. Not all clients answer such queries, e.g. jabber.el doesn't. This command can also tell the uptime of a server or component. The first of these commands uses the old Entity Time protocol (*note XEP-0090::). It has been superseded by XEP-0202, but jabber.el doesn't implement the newer protocol yet. The latter two commands use the Last Activity protocol (*note XEP-0012::).  File: jabber.info, Node: Useful features, Next: Message history, Prev: Time queries, Up: Top 10 Useful features ****************** jabber.el includes a number of features meant to improve the user interface and do other useful things. * Menu: * Autoaway:: * Modeline status:: * Keepalive:: * Reconnecting:: * Tracking activity:: * Watch buddies:: * Spell checking::  File: jabber.info, Node: Autoaway, Next: Modeline status, Prev: Useful features, Up: Useful features 10.1 Autoaway ============= It is possible to automatically set your status to "away" when you haven't used your computer for a while. This lets your contacts know that you might not answer immediately. To activate this feature, add `jabber-autoaway-start' to `jabber-post-connect-hooks', e.g: (add-hook 'jabber-post-connect-hooks 'jabber-autoaway-start) There are different methods to find how long you have been "idle". The method to use is specified by `jabber-autoaway-method'. The value of this variable should be a function that returns the number of seconds you have been idle. Three functions are provided. If your Emacs has the `current-idle-time' function (which was introduced in Emacs 22), it is used by default. Note that this method only measures the time since you last interacted with Emacs, and thus disregards activity in other programs. If you are using the X Window System, you can use the xprintidle program.(1) Make sure that `jabber-xprintidle-program' is set to the correct file name. This uses the same method as XScreensaver (http://www.jwz.org/xscreensaver) to find your idle time. If you use the xscreensaver program, you can use the `xscreensaver-emacs-jabber' Perl script to synchronize xscreensaver and jabber.el status. It is a simple Perl daemon that watches for xscreensaver status and sets jabber.el's presence when needed. I.e.: it sets XA presence when the screen is blanked or locked (by hands or by idle timeout) and default presence when it's unlocked/unblanked. To use it, just run `xscreensaver-emacs-jabber' after xscreensaver and make sure that your Emacs run in server mode (that you run `(server-start)' in init files; *note Using Emacs as a Server: (emacs)Emacs Server. Alternatively, you can turn on and off server-mode by jabber.el's hooks). If you are using Emacs on a GNU/Linux terminal, the function `jabber-termatime-get-idle-time' is used by default. It uses the access time of the terminal device as a measure of idle time. ---------- Footnotes ---------- (1) `http://www.dtek.chalmers.se/~henoch/text/xprintidle.html'  File: jabber.info, Node: Modeline status, Next: Keepalive, Prev: Autoaway, Up: Useful features 10.2 Modeline status ==================== By typing `M-x jabber-mode-line-mode' you toggle display of some status in mode lines. The information is your own presence status, and some numbers showing the status of your roster contacts. By default, there are three numbers, for "online" (chatty and online), "away" (away, extended away and do not disturb) and offline contacts. If you set `jabber-mode-line-compact' to nil, you get a complete breakdown of presence status. That gives you six numbers indicating the number of chatty, online, away, extended away, dnd, and offline contacts, respectively.  File: jabber.info, Node: Keepalive, Next: Reconnecting, Prev: Modeline status, Up: Useful features 10.3 Keepalive ============== Sometimes network connections are lost without you noticing. This is especially true with Jabber, as it is quite reasonable to keep the connection open for a long time without either sending or receiving any data. On the other hand, the server may want to do the same kind of detection, and may expect the client to send something at regular intervals. If you want to detect a lost connection earlier, or make sure that the server doesn't drop your connection, you can use the keepalive functions. These come in two flavours: whitespace pings and XMPP pings. 10.3.1 Whitespace pings ----------------------- A "whitespace ping" is a single space character sent to the server. This is often enough to make NAT devices consider the connection "alive", and likewise for certain Jabber servers, e.g. Openfire. It may also make the OS detect a lost connection faster--a TCP connection on which no data is sent or received is indistinguishable from a lost connection. Type `M-x jabber-whitespace-ping-start' to start it, and `M-x jabber-whitespace-ping-stop' to stop it. The former is in `jabber-post-connect-hooks' by default; *note Hooks::. The frequency of whitespace pings is controlled by the variable `jabber-whitespace-ping-interval'. The default value is once every 30 seconds. 10.3.2 XMPP pings ----------------- These functions work by sending a ping request to your server once in a while (by default every ten minutes), and considering the connection lost if the server doesn't answer within reasonable time (by default 20 seconds). Type `M-x jabber-keepalive-start' to start it, and `M-x jabber-keepalive-stop' to stop it. You may want to add `jabber-keepalive-start' to `jabber-post-connect-hooks'; *note Hooks::. You can customize the interval and the timeout with the variables `jabber-keepalive-interval' and `jabber-keepalive-timeout', respectively.  File: jabber.info, Node: Reconnecting, Next: Tracking activity, Prev: Keepalive, Up: Useful features 10.4 Reconnecting ================= jabber.el supports automatic reconnection to Jabber server(s) upon lost connection. By default it is off. To turn on, customize the `jabber-auto-reconnect' variable. This is of limited use if you have to type your password every time jabber.el reconnects. There are two ways to save your password: you can set it in `jabber-account-alist' (*note Account settings::), and you can use `password-cache.el', which is available in recent versions of Gnus and in Emacs 23. Note that you probably want to customize `password-cache-expiry' if you use the latter.  File: jabber.info, Node: Tracking activity, Next: Watch buddies, Prev: Reconnecting, Up: Useful features 10.5 Tracking activity ====================== When you're working on something important you might want to delay responding to incoming messages. However, when you're done working, will you remember them? If you're anything like me, you'll have a lot of buffers in your Emacs session, and a Jabber chat buffer can easily get lost. When `jabber-activity-mode' is enabled (by default, it is), Emacs keeps track of the buddies which have messaged you since last you visited their buffer, and will display them in mode line. As soon as you visit their buffer they disappear from the mode line, indicating that you've read their message. If your mode line fills over because of these notifications, you can customize `jabber-activity-make-strings' to shorten them to the shortest possibly unambiguous form. If you try to exit Emacs while you still have unread messages, you will be notified and asked about this. If you don't like that, set `jabber-activity-query-unread' to nil. If you want to display the number of unread buffers in the frame title, set `jabber-activity-count-in-title' to t. The format of the number can be changed through `jabber-activity-count-in-title-format'. To hide activity notifications for some contacts, use `jabber-activity-banned' variable - just add boring JIDs (as regexps) here. For complete customizability, write a hook function for `jabber-activity-update-hook'. From that function, you can take action based on `jabber-activity-jids', `jabber-activity-mode-string', and `jabber-activity-count-string'.  File: jabber.info, Node: Watch buddies, Next: Spell checking, Prev: Tracking activity, Up: Useful features 10.6 Watch buddies ================== Sometimes you might be waiting for a certain person to come online, and you don't want that occasion to get lost in the noise. To get an obtrusive message when that happens, type `M-x jabber-watch-add' and select the person in question. You can enter a comment, to remember why you added the watch. You will get a message whenever that person goes from offline to online. jabber.el will remember this for the rest of your Emacs session (it's not saved to disk, though), but if you want to get rid of it, type `M-x jabber-watch-remove'.  File: jabber.info, Node: Spell checking, Prev: Watch buddies, Up: Useful features 10.7 Spell checking =================== You can activate spell checking in a chat buffer with `M-x flyspell-mode'. It will check only what you are currently writing, not what you receive or what you have already sent. You may want to add `flyspell-mode' to `jabber-chat-mode-hook'. For more information about Emacs spell checking, *note Checking and Correcting Spelling: (emacs)Spelling.  File: jabber.info, Node: Message history, Next: Typing notifications, Prev: Useful features, Up: Top 11 Message history ****************** If you want a record of messages sent and received, set `jabber-history-enabled' to t. By default all messages will be saved to a global history file specified by `jabber-global-history-filename' (`~/.jabber_global_message_log' by default). If you prefer to store your chats' history in per-contact files, you can set `jabber-use-global-history' to `nil'. When using per-contact history, files are named by the contact JID and saved under the directory specified by the variable `jabber-history-dir' (default is `~/.emacs-jabber'). When you open a new chat buffer and have entries in your history file, the last few messages you recently exchanged with the contact in question will be inserted. You can control how many messages with `jabber-backlog-number' (by default 10), and how old messages with `jabber-backlog-days' (by default 3 days). If you want to see more messages, use the function `jabber-chat-display-more-backlog', available in the Chat menu. This is currently the only way to view the message history, apart from opening the history files manually. If you worry about your history file(s) size, you can enable history rotation feature by setting the variable `jabber-history-enable-rotation' to `t' (default is `nil'). This feature "rotates" your history files according to the following rule: When `jabber-history-size-limit' (in kilobytes) is reached, the HISTORY-FILE is renamed to `HISTORY-FILE-NUMBER', where NUMBER is 1 or the smallest number after the last rotation. For example, suppose you set the `jabber-history-size-limit' variable to 512 and you chat with your buddy `foo@jabber.server' using the per-contact strategy to store history files. So, when the history file (`foo@jabber-server') reaches 512K bytes, it will be renamed to `foo@jabber-server-1' and `foo@jabber-server' will be set empty. Next time `foo@jabber-server' grows to 512K bytes, it will be saved as `foo@jabber-server-2' and so on. Although the example was presented with the per-contact history file strategy, history rotation works for both per-contact and global history logging strategies. If you also want to keep chat and groupchat buffers from growing too much, you can customize `jabber-alert-message-hooks' and `jabber-alert-muc-hooks' by adding truncation upon receiving message (`jabber-truncate-chat' and `jabber-truncate-muc', respectively). The truncation limit may be set by customizing the variable `jabber-log-lines-to-keep'.  File: jabber.info, Node: Typing notifications, Next: Roster import and export, Prev: Message history, Up: Top 12 Typing notifications *********************** There are two protocols for "contact is typing" notifications in Jabber. jabber.el supports both of them, displaying various information in the header line of chat buffers. 12.1 Message events =================== The older protocol is called Message Events (*note XEP-0022::). Besides typing notification, it lets you know what happens to the messages you send. These states are possible: * `In offline storage' (the user will receive it on next logon) * `Delivered' to user's client (but not necessarily displayed) * `Displayed' to user * User is `typing a message' The first state is only reported by servers; the other three are reported by clients. jabber.el can report all three of them, and can display all four; not all clients support all states, though. If you don't want jabber.el to send out this information about you, set the variables `jabber-events-confirm-delivered', `jabber-events-confirm-displayed', and/or `jabber-events-confirm-composing' to nil. You can make jabber.el not to request such information by customizing `jabber-events-request-these'. 12.2 Chat states ================ The newer protocol is called Chat States (*note XEP-0085::). Rather than dealing with individual messages, it describes the state of the chat session between two people. The following states are possible: * Active (the default state, not displayed) * Inactive * Composing * Paused (i.e., taking a short pause in composing) * Gone jabber.el can display all five states, but only ever sends "active" and "composing" itself. To customize sending of chat states, customize the variable `jabber-chatstates-confirm'.  File: jabber.info, Node: Roster import and export, Next: XMPP URIs, Prev: Typing notifications, Up: Top 13 Roster import and export *************************** Your roster is saved on the Jabber server, and usually not in the client. However, you might want to save the roster to a file anyway. The most common reason for this is probably to copy it to another account. To export your roster to a file, type `M-x jabber-export-roster'. A buffer will appear in which you can edit the data to be exported. Changes done in that buffer will not affect your real roster. To import your roster from a file, type `M-x jabber-import-roster'. You will be able to edit the data before importing it. Items not in the roster will be added; items in the roster will be modified to match imported data. Subscriptions will be updated. The format of the roster files is the XML used by roster pushes in the XMPP protocol, in UTF-8 encoding.  File: jabber.info, Node: XMPP URIs, Next: Customization, Prev: Roster import and export, Up: Top 14 XMPP URIs ************ Many web page authors use links starting with `xmpp:' for JIDs. Your web browser could be made to pass such links to jabber.el, so that such links are actually useful and not just decoration. How to do that depends on your operating system and web browser. For any of these methods, you need to make sure that you are running the Emacs server. *Note Using Emacs as a Server: (emacs)Emacs Server, though the simplest way to start it is to customize the variable `server-mode'. 14.1 GNOME ========== The jabber.el distribution contains a GConf schema which tries to set up handling of `xmpp:' URIs. It is installed by `make install'. This may or may not work, depending on your GConf configuration and other installed applications. To check, try running: gconftool --get /desktop/gnome/url-handlers/xmpp/command This should print something like: /usr/local/libexec/emacs-jabber-uri-handler "%s" This setting is picked up by most GNOME or GTK based web browsers, including Firefox. 14.2 Mozilla and Unix ===================== If you use a Mozilla-based web browser on a Unix-like operating system, and the GConf method above doesn't work, you can set it up manually by following these steps: 1. Note the path of the `emacs-jabber-uri-handler' file in the jabber.el distribution, and make sure it is executable. 2. Set the Mozilla preference `network.protocol-handler.app.xmpp' to the path of `emacs-jabber-uri-handler'. There are two ways to do this: * Go to the URL `about:config', right-click in the list, choose "New string", and enter `network.protocol-handler.app.xmpp' and the path in the following dialogs. * Open or create the file `user.js' in your Mozilla profile directory (in the same directory as `prefs.js'), and add the following line: user_pref("network.protocol-handler.app.xmpp", "/PATH/TO/emacs-jabber-uri-handler"); Restart Mozilla for this change to take effect. 14.3 Other systems ================== If you know how to pass an XMPP URI from your browser to the function `jabber-handle-uri', your contribution for this section would be appreciated.  File: jabber.info, Node: Customization, Next: Hacking and extending, Prev: XMPP URIs, Up: Top 15 Customization **************** jabber.el is intended to be customizable for many tastes. After all, this is Emacs. To open a customization buffer for jabber.el, type `M-x jabber-customize'. * Menu: * Account settings:: * Menu:: * Customizing the roster buffer:: * Customizing the chat buffer:: * Customizing alerts:: * Hooks:: * Debug options::  File: jabber.info, Node: Account settings, Next: Menu, Prev: Customization, Up: Customization 15.1 Account settings ===================== All account settings reside in the variable `jabber-account-list'. Usually you only need to set the JID, in the form `username@server' (or `username@server/resource' to use a specific resource name). These are the other account options: Disabled If the account is disabled, `jabber-connect-all' will not attempt to connect it. You can still connect it manually with `jabber-connect'. Password You can set the password of the account, so you don't have to enter it when you connect. Note that it will be stored unencrypted in your customization file. Network server If the JID of the Jabber server is not also its DNS name, you may have to enter the real DNS name or IP address of the server here. Connection type This option specifies whether to use an encrypted connection to the server. Usually you want "STARTTLS" (`starttls'), which means that encryption is activated if the server supports it. The other possibilities are "unencrypted" (`network'), which means just that, and "legacy SSL/TLS" (`ssl'), which means that encryption is activated on connection. Port If the Jabber server uses a nonstandard port, specify it here. The default is 5222 for STARTTLS and unencrypted connections, and 5223 for legacy SSL connections. 15.1.1 For Google Talk ---------------------- If you have a very new version of `dns.el',(1) you can connect to Google Talk just by specifying your Gmail address as JID. Otherwise, you also need to set "network server" to `talk.google.com' and "connection type" to "legacy SSL". 15.1.2 Upgrade note ------------------- Previous versions of jabber.el had the variables `jabber-username', `jabber-server', `jabber-resource' and `jabber-password'. These are now obsolete and not used. ---------- Footnotes ---------- (1) Specifically, you need Emacs 23, or No Gnus 0.3.  File: jabber.info, Node: Menu, Next: Customizing the roster buffer, Prev: Account settings, Up: Customization 15.2 Menu ========= There is a Jabber menu on the menu bar with some common commands. By default, it is displayed only if you are connected, or if you have configured any accounts. You can set the variable `jabber-display-menu' to `t' or `nil', to have the menu displayed always or never, respectively. The default behaviour corresponds to the setting `maybe'. Earlier, the way to have the menu appear was to call the function `jabber-menu'. It still works, but is considered obsolete.  File: jabber.info, Node: Customizing the roster buffer, Next: Customizing the chat buffer, Prev: Menu, Up: Customization 15.3 Customizing the roster buffer ================================== `jabber-roster-sort-functions' controls how roster items are sorted. By default, contacts are sorted first by presence, and then alphabetically by displayed name. `jabber-sort-order' controls how roster items are sorted by presence. It is a list containing strings corresponding to show status (*note Presence::) or `nil', which represents offline. `jabber-show-resources' controls when your contacts' resources are shown in the roster buffer. The default is to show resources when a contact has more than one connected resource. `jabber-roster-line-format' specifies how the entry for each contact looks. It is a string where some characters are special if preceded by a percent sign: `%a' Avatar of contact, if any `%c' `*' if the contact is connected, or ` ' if not `%u' Subscription state--see below `%n' Nickname of contact, or JID if no nickname `%j' Bare JID of contact (without resource) `%r' Highest-priority resource of contact `%s' Availability of contact as a string ("Online", "Away" etc) `%S' Status string specified by contact `jabber-roster-show-title' controls whether to show a "Jabber roster" string at the top of the roster buffer. You need to run `M-x jabber-display-roster' after changing this variable to update the display. `%u' is replaced by one of the strings given by `jabber-roster-subscription-display'. `jabber-resource-line-format' is nearly identical, except that the values correspond to the values of the resource in question, and that the `%p' escape is available, which inserts the priority of the resource. `jabber-roster-buffer' specifies the name of the roster buffer. If you change this, the new name will be used the next time the roster is redisplayed. `jabber-roster-show-bindings' controls whether to show a list of keybindings at the top of the roster buffer. You need to run `M-x jabber-display-roster' after changing this variable to update the display.  File: jabber.info, Node: Customizing the chat buffer, Next: Customizing alerts, Prev: Customizing the roster buffer, Up: Customization 15.4 Customizing the chat buffer ================================ You can customize the look of the prompts in the chat buffer. There are separate settings for local text (i.e. what you write) and foreign text (i.e. what other people write). `jabber-chat-text-local' and `jabber-chat-text-foreign' determine the faces used for chat messages. `jabber-chat-prompt-local' and `jabber-chat-prompt-foreign' determine the faces used for the prompts. `jabber-chat-local-prompt-format' and `jabber-chat-foreign-prompt-format' determine what text is displayed in the prompts. They are format strings, with the following special sequences defined: `%t' The time when the message was sent or received `%n' The nickname of the user. For the foreign prompt, this is the name of the contact in the roster, or the JID if no name set. For the local prompt, this is the username part of your JID. `%u' The username of the user (i.e. the first part of the JID). `%r' The resource. `%j' The bare JID of the user `jabber-chat-time-format' defines how `%t' shows time. Its format is identical to that passed to `format-time-string'. *Note Time Conversion: (elisp)Time Conversion. `jabber-chat-delayed-time-format' is used instead of `jabber-chat-time-format' for delayed messages (messages sent while you were offline, or fetched from history). This way you can have short timestamps everywhere except where you need long ones. You can always see the complete timestamp in a tooltip by hovering over the prompt with the mouse. By default, timestamps are printed in the chat buffer every hour (at "rare" times). This can be toggled with `jabber-print-rare-time'. You can customize the displayed time by setting `jabber-rare-time-format'. Rare timestamps will be printed whenever time formatted by that format string would change. You can also customize the header line of chat buffers, by modifying the variable `jabber-chat-header-line-format'. The format of that variable is the same as that of `mode-line-format' and `header-line-format'. *Note Mode-Line Format: (elisp)Mode Line Format. For MUC buffers, `jabber-muc-header-line-format' is used instead. The variable `jabber-chat-fill-long-lines' controls whether long lines in the chat buffer are wrapped.  File: jabber.info, Node: Customizing alerts, Next: Hooks, Prev: Customizing the chat buffer, Up: Customization 15.5 Customizing alerts ======================= When an event happens (currently including presence changes, incoming messages, and completed queries) you will usually want to be notified. Since tastes in this area vary wildly, these alerts are implemented as hooks, so you can choose which ones you want, or write your own if none fit. Actually, if you don't want to write your own, stop reading this section and just read *note Standard alerts::. Many kinds of alerts consist in displaying a text message through a certain mechanism. This text message is provided by a function which you can rewrite or replace. If this function returns `nil', no message is displayed, and non-textual alerts refrain from action. If you want to write alert hooks that do nothing except displaying the supplied message in some way, use the macro `define-jabber-alert'. For example, if FOO is a function that takes a string as an argument, write (define-jabber-alert foo "Display a message in a fooish way" 'foo) and all details will be taken care of for you. The hooks take different arguments depending on category. However, they all have in common that the last argument is the result of the message function. The message function for each category takes the same arguments as the corresponding hooks, except for that last argument. Alert hook contributions are very welcome. You can send them to the mailing list, or to the Sourceforge patch tracker. Alert hooks are meant for optional UI things, that are subject to varying user tastes, and that can be toggled by simply adding or removing the function to and from the hook. For other purposes, there are corresponding general hooks, that are defvars instead of defcustoms, and that are meant to be managed by Lisp code. They have the same name as the alert hooks minus the `-alert' part, e.g. `jabber-message-hooks' vs `jabber-alert-message-hooks', etc. * Menu: * Standard alerts:: * Presence alerts:: * Message alerts:: * MUC alerts:: * Info alerts::  File: jabber.info, Node: Standard alerts, Next: Presence alerts, Prev: Customizing alerts, Up: Customizing alerts 15.5.1 Standard alerts ---------------------- Thirteen alerts are already written for all four alert categories. These all obey the result from the corresponding message function. The `beep' alerts simply sound the terminal bell by calling `ding'. They are disabled by default. The `echo' alerts display a message in the echo area by calling `message'. They are enabled by default. The `switch' alerts switch to the buffer where the event occurred (chat buffer for incoming messages, roster buffer for presence changes, browse buffer for completed queries). They are disabled by default. Take care when using them, as they may interrupt your editing. The `display' alerts display but do not select the buffer in question, using the function `display-buffer'. *Note Choosing a Window for Display: (elisp)Choosing Window, for information about customizing its behaviour. This is enabled by default for info requests. The `wave' alerts play a sound file by calling `play-sound-file'. No sound files are provided. To use this, enter the names of the sound files in `jabber-alert-message-wave', `jabber-alert-presence-wave' and `jabber-alert-info-wave', respectively. You can specify specific sound files for contacts matching a regexp in the variables `jabber-alert-message-wave-alist' and `jabber-alert-presence-wave-alist'. The `screen' alerts send a message through the Screen terminal manager(1). They do no harm if called when you don't use Screen. The `ratpoison' alerts send a message through the Ratpoison window manager(2). They do no harm if used when you're not running X, but if you are running X with another window manager, the ratpoison processes will never exit. Emacs doesn't hold on to them, though. The `sawfish' alerts send a message through the Sawfish window manager. The `wmii' alerts display a message through the wmii window manager. The `xmessage' alerts send a message through the standard `xmessage' tool. The variable `jabber-xmessage-timeout' controls how long the alert appears. The `osd' alerts send a message onto your screen using XOSD.(3) The `libnotify' alerts send a message onto your screen using `notification-daemon'. The `festival' alerts speak the message using the Emacs interface of the Festival speech synthesis system(4). The `autoanswer' alert is kind of special: it will not show you message/muc alert, but instead will automaticaly answer to sender. See variable `jabber-autoanswer-alist' description for details. Additionally, for one-to-one and MUC messages, there are `scroll' alerts (enabled by default), that aim to do the right thing with chat buffers that are visible but not active. Sometimes you want point to scroll down, and sometimes not. These functions should do what you mean; if they don't, it's a bug. Also, in MUC you can use a family of so-called "personal" alerts. They are like other MUC alerts, but fire only on incoming messages addresed directly to you (also known as "private messages"). One example of such an alert is `jabber-muc-echo-personal', which shows a note for an MUC message only if it was addressed to you. Some of these functions are in the `jabber-alert.el' file, and the others are in their own files. You can use them as templates or inspiration for your own alerts. ---------- Footnotes ---------- (1) See `http://www.gnu.org/software/screen/'. (2) See `http://ratpoison.sourceforge.net/'. (3) XOSD can be found at `http://www.ignavus.net/software.html'. You also need `osd.el' from `http://www.brockman.se/software/osd.el'. (4) See `http://www.cstr.ed.ac.uk/projects/festival/'.  File: jabber.info, Node: Presence alerts, Next: Message alerts, Prev: Standard alerts, Up: Customizing alerts 15.5.2 Presence alerts ---------------------- Set `jabber-alert-presence-message-function' to your desired function. This function should look like: (defun FUNCTION (WHO OLDSTATUS NEWSTATUS STATUSTEXT) ... ) WHO is the JID symbol (*note JID symbols::), OLDSTATUS and NEWSTATUS are the previous and current stati, respectively, and STATUSTEXT is the status message if provided, otherwise nil. OLDSTATUS and NEWSTATUS can be one of `""' (i.e. online), `"away"', `"xa"', `"dnd"', `"chat"', `"error"' and `nil' (i.e. offline). NEWSTATUS can also be one of `"subscribe"', `"subscribed"', `"unsubscribe"' and `"unsubscribed"'. The default function, `jabber-presence-default-message', returns `nil' if OLDSTATUS and NEWSTATUS are the same, and in other cases constructs a message from the given data. Another function, `jabber-presence-only-chat-open-message', behave just like `jabber-presence-default-message', but only if conversation buffer for according JID is already open. Use it to show presence notifications only for "interesting" contacts. All presence alert hooks take the same arguments plus the additional PROPOSED-ALERT, which is the result of the specified message function. This last argument is usually the only one they use.  File: jabber.info, Node: Message alerts, Next: MUC alerts, Prev: Presence alerts, Up: Customizing alerts 15.5.3 Message alerts --------------------- Set `jabber-alert-message-function' to your desired function.(1) This function should look like: (defun FUNCTION (FROM BUFFER TEXT) ... ) FROM is the JID symbol (*note JID symbols::), BUFFER is the buffer where the message is displayed, and TEXT is the text of the message. The default function, `jabber-message-default-message', returns "Message from PERSON", where PERSON is the name of the person if specified in the roster, otherwise the JID. All message alert hooks take the same arguments plus the additional PROPOSED-ALERT, which is the result of the specified message function. If you don't want message alerts when the chat buffer in question is already the current buffer, set `jabber-message-alert-same-buffer' to nil. This affects the behaviour of the default message function, so you'll have to reimplement this functionality if you write your own message function. ---------- Footnotes ---------- (1) Logically it should be `jabber-alert-message-message-function', but that would be really ugly.  File: jabber.info, Node: MUC alerts, Next: Info alerts, Prev: Message alerts, Up: Customizing alerts 15.5.4 MUC alerts ----------------- Set `jabber-alert-muc-function' to your desired function. This function should look like: (defun FUNCTION (NICK GROUP BUFFER TEXT) ... ) NICK is the nickname, GROUP is the JID of the group, BUFFER is the buffer where the message is displayed, and TEXT is the text of the message. The default function, `jabber-muc-default-message', returns "Message from NICK in GROUP" or "Message in GROUP", the latter for messages from the room itself. All MUC alert hooks take the same arguments plus the additional PROPOSED-ALERT, which is the result of the specified message function. By default, no alert is made for messages from yourself. To change that, customize the variable `jabber-muc-alert-self'.  File: jabber.info, Node: Info alerts, Prev: MUC alerts, Up: Customizing alerts 15.5.5 Info alerts ------------------ Info alerts are sadly underdeveloped. The message function, `jabber-alert-info-message-function', takes two arguments, INFOTYPE and BUFFER. BUFFER is the buffer where something happened, and INFOTYPE is either `'roster' for roster updates, or `'browse' for anything that uses the browse buffer (basically anything except chatting). The info alert hooks take an extra argument, as could be expected.  File: jabber.info, Node: Hooks, Next: Debug options, Prev: Customizing alerts, Up: Customization 15.6 Hooks ========== jabber.el provides various hooks that you can use for whatever purpose. `jabber-post-connect-hooks' This hook is called after successful connection and authentication. By default it contains `jabber-send-current-presence' (*note Presence::). The hook functions get the connection object as argument. `jabber-lost-connection-hooks' This hook is called when you have been disconnected for unknown reasons. Usually this isn't noticed for quite a long time. The hook is called with one argument: the connection object. `jabber-pre-disconnect-hook' This hook is called just before voluntary disconnection, i.e. in `jabber-disconnect', the command to disconnect all accounts. There is currently no hook for disconnection of a single account. `jabber-post-disconnect-hook' This hook is called after disconnection of any kind, possibly just after `jabber-lost-connection-hook'. `jabber-chat-mode-hook' This hook is called when a new chat buffer is created. `jabber-browse-mode-hook' This hook is called when a new browse buffer is created. `jabber-roster-mode-hook' This hook is called when the roster buffer is created.  File: jabber.info, Node: Debug options, Prev: Hooks, Up: Customization 15.7 Debug options ================== These settings provide a lot of information which is usually not very interesting, but can be useful for debugging various things. `jabber-debug-log-xml' activates XML logging. All XML stanzas sent and received are logged in the buffer `*-jabber-xml-log-JID-*' in list format. *Note XML representation::. Usually, the process buffers for Jabber connections are killed when the connection is closed, as they would otherwise just fill up memory. However, they might contain information about why the connection was lost. To keep process buffers, set `jabber-debug-keep-process-buffers' to `t'.  File: jabber.info, Node: Hacking and extending, Next: Protocol support, Prev: Customization, Up: Top 16 Hacking and extending ************************ This part of the manual is an attempt to explain parts of the source code. It is not meant to discourage you from reading the code yourself and trying to figure it out, but as a guide on where to look. Knowledge of Jabber protocols is assumed. * Menu: * Connection object:: * XML representation:: * JID symbols:: * Listening for new requests:: * Sending new requests:: * Extending service discovery:: * Chat printers:: * Stanza chains::  File: jabber.info, Node: Connection object, Next: XML representation, Prev: Hacking and extending, Up: Hacking and extending 16.1 Connection object ====================== Each Jabber connection is represented by a "connection object". This object has the form of a finite state machine, and is realized by the library `fsm'.(1) The various states of this object are defined in `jabber-core.el'. They describe the way of the connection through the establishing of a network connection and authentication, and finally comes to the `:session-established' state where ordinary traffic takes place. These details are normally opaque to an extension author. As will be noted, many functions expect to receive a connection object, and functions at extension points generally receive such an object in order to pass it on. The following functions simply query the internal state of the connection: -- Function: jabber-connection-jid connection The `jabber-connection-jid' function returns the full JID of CONNECTION, i.e. a string of the form `"username@server/resource"'. -- Function: jabber-connection-bare-jid connection The `jabber-connection-bare-jid' function returns the bare JID of CONNECTION, i.e. a string of the form `"username@server"'. ---------- Footnotes ---------- (1) So far, this library is only distributed with jabber.el. The author hopes that it could be useful for other projects, too.  File: jabber.info, Node: XML representation, Next: JID symbols, Prev: Connection object, Up: Hacking and extending 16.2 XML representation ======================= The XML representation is the one generated by `xml.el' in Emacs, namely the following. Each tag is a list. The first element of the list is a symbol, the name of which is the name of the tag. The second element is an alist of attributes, where the keys are the attribute names in symbol form, and the values are strings. The remaining elements are the tags and data contained within the tag. For example, Fnord is represented as (foo ((bar . "baz")) (frobozz nil "") "Fnord ") Note the empty string as the third element of the `frobozz' list. It is not present in newer (post-21.3) versions of `xml.el', but it's probably best to assume it might be there. -- Function: jabber-sexp2xml xml-sexp This function takes a tag in list representation, and returns its XML representation as a string. You will normally not need to use this function directly, but it can be useful to see how your sexps will look when sent to the outer, non-Lisp, world. -- Function: jabber-send-sexp connection sexp This function sends SEXP, an XMPP stanza in list representation, and sends it over CONNECTION. You will normally use the functions `jabber-send-presence', `jabber-send-message' and `jabber-send-iq' instead of this function.  File: jabber.info, Node: JID symbols, Next: Listening for new requests, Prev: XML representation, Up: Hacking and extending 16.3 JID symbols ================ JIDs are sometimes represented as symbols. Its name is the JID, and it is interned in `jabber-jid-obarray'. A roster entry can have the following properties: `xml' The XML tag received from the server on roster update `name' The name of the roster item (just like the XML attribute) `subscription' The subscription state; a string, one of `"none"', `"from"', `"to"' and `"both"' `ask' The ask state; either `nil' or `"subscribe"' `groups' A list of strings (possibly empty) containing all the groups the contact is in `connected' Boolean, true if any resource is connected `show' Presence show value for highest-priority connected resource; a string, one of `""' (i.e. online), `"away"', `"xa"', `"dnd"', `"chat"', `"error"' and `nil' (i.e. offline) `status' Presence status message for highest-priority connected resource `resources' Alist. Keys are strings (resource names), values are plists with properties `connected', `show', `status' and `priority'. Incoming presence information is inserted in `resources', and the information from the resource with the highest priority is inserted in `show' and `status' by the function `jabber-prioritize-resources'.  File: jabber.info, Node: Listening for new requests, Next: Sending new requests, Prev: JID symbols, Up: Hacking and extending 16.4 Listening for new requests =============================== To listen for new IQ requests, add the appropriate entry in `jabber-iq-get-xmlns-alist' or `jabber-iq-set-xmlns-alist'. The key is the namespace of the request, and the value is a function that takes two arguments, the connection object, and the entire IQ stanza in list format. `jabber-process-iq' reads these alists to determine which function to call on incoming packets. For example, the Ad-Hoc Commands module contains the following: (add-to-list 'jabber-iq-set-xmlns-alist (cons "http://jabber.org/protocol/commands" 'jabber-ahc-process)) To send a response to an IQ request, use `(jabber-send-iq CONNECTION SENDER "result" QUERY nil nil nil nil ID)', where QUERY is the query in list format. `jabber-send-iq' will encapsulate the query in an IQ packet with the specified id. To return an error to the Jabber entity that sent the query, use `jabber-signal-error'. The signal is caught by `jabber-process-iq', which takes care of sending the error. You can also use `jabber-send-iq-error'.  File: jabber.info, Node: Sending new requests, Next: Extending service discovery, Prev: Listening for new requests, Up: Hacking and extending 16.5 Sending new requests ========================= To send an IQ request, use `jabber-send-iq'. It will generate an id, and create a mapping for it for use when the response comes. The syntax is: (jabber-send-iq CONNECTION TO TYPE QUERY SUCCESS-CALLBACK SUCCESS-CLOSURE FAILURE-CALLBACK FAILURE-CLOSURE) SUCCESS-CALLBACK will be called if the response is of type `result', and FAILURE-CALLBACK will be called if the response is of type `error'. Both callbacks take three arguments, the connection object, the IQ stanza of the response, and the corresponding closure item earlier passed to `jabber-send-iq'. Two standard callbacks are provided. `jabber-report-success' takes a string as closure item, and reports success or failure in the echo area by appending either `succeeded' or `failed' to the string. `jabber-process-data' prepares a browse buffer. If its closure argument is a function, it calls that function with point in this browse buffer. If it's a string, it prints that string along with the error message in the IQ response. If it's anything else (e.g. `nil'), it just dumps the XML in the browse buffer. Examples follow. This is the hypothetical Jabber protocol "frob", for which only success report is needed: (jabber-send-iq connection "someone@somewhere.org" "set" '(query ((xmlns . "frob"))) 'jabber-report-success "Frobbing" 'jabber-report-success "Frobbing") This will print "Frobbing succeeded" or "Frobbing failed: REASON", respectively, in the echo area. The protocol "investigate" needs to parse results and show them in a browse buffer: (jabber-send-iq connection "someone@somewhere.org" "get" '(query ((xmlns . "investigate"))) 'jabber-process-data 'jabber-process-investigate 'jabber-process-data "Investigation failed") Of course, the previous example could have used `jabber-report-success' for the error message. It's a matter of UI taste.  File: jabber.info, Node: Extending service discovery, Next: Chat printers, Prev: Sending new requests, Up: Hacking and extending 16.6 Service discovery ====================== Service discovery (XEP-0030) is a Jabber protocol for communicating features supported by a certain entity, and items affiliated with an entity. jabber.el has APIs for both providing and requesting such information. * Menu: * Providing info:: * Requesting info::  File: jabber.info, Node: Providing info, Next: Requesting info, Prev: Extending service discovery, Up: Extending service discovery 16.6.1 Providing info --------------------- Your new IQ request handlers will likely want to advertise their existence through service discovery. To have an additional feature reported in response to disco info requests, add a string to `jabber-advertised-features'. By default, the service discovery functions reject all requests containing a node identifier with an "Item not found" error. To make them respond, add the appropriate entries to `jabber-disco-items-nodes' and `jabber-disco-info-nodes'. Both variables work in the same way. They are alists, where the keys are the node names, and the values are lists of two items. The first item is the data to return -- either a list, or a function taking the connection object and the entire IQ stanza and returning a list; in either case this list contains the XML nodes to include in the `' node in the response. The second item is the access control function. An access control function receives the connection object and a JID as arguments, and returns non-nil if access is to be granted. If nil is specified instead of a function, access is always granted. One such function is provided, `jabber-my-jid-p', which grants access for JIDs where the username and server (not necessarily resource) are equal to those of the user, or one of the user's configured accounts.  File: jabber.info, Node: Requesting info, Prev: Providing info, Up: Extending service discovery 16.6.2 Requesting info ---------------------- jabber.el has a facility for requesting disco items and info. All positive responses are cached. To request disco items or info from an entity, user one of these functions: -- Function: jabber-disco-get-info jc jid node callback closure-data &optional force Get disco information for JID and NODE. A request is sent asynchronously on the connection JC. When the response arrives, CALLBACK is called with three arguments: JC, CLOSURE-DATA, and the result. The result may be retrieved from the cache, unless FORCE is non-nil. If the request was successful, or retrieved from cache, it looks like `(IDENTITIES FEATURES)', where IDENTITIES and FEATURES are lists. Each identity is `["NAME" "CATEGORY" "TYPE"]', and each feature is a string denoting the namespace of the feature. If the request failed, the result is an `' node. -- Function: jabber-disco-get-items jc jid node callback closure-data &optional force Get disco information for JID and NODE. A request is sent asynchronously on the connection JC. When the response arrives, CALLBACK is called with three arguments: JC, CLOSURE-DATA, and the result. The result may be retrieved from the cache, unless FORCE is non-nil. If the request was successful, or retrieved from cache, the result is a list of items, where each item is `["NAME" "JID" "NODE"]'. The values are either strings or nil. If the request failed, the result is an `' node. If you only want to see what is in the cache, use one of the following functions. They don't use a callback, but return the result directly. -- Function: jabber-disco-get-info-immediately jid node Return cached disco information for JID and NODE, or nil if the cache doesn't contain this information. The result is the same as for `jabber-disco-get-info'. -- Function: jabber-disco-get-items-immediately jid node Return cached disco items for JID and NODE, or nil if the cache doesn't contain this information. The result is the same as for `jabber-disco-get-items'. In the future, this facility will be expanded to provide information acquired through XEP-0115, Entity capabilities, which is a protocol for sending disco information in `' stanzas.  File: jabber.info, Node: Chat printers, Next: Stanza chains, Prev: Extending service discovery, Up: Hacking and extending 16.7 Chat printers ================== Chat printers are functions that print a certain aspect of an incoming message in a chat buffer. Included are functions for printing subjects (`jabber-chat-print-subject'), bodies (`jabber-chat-print-body', and `jabber:x:oob'-style URLs (`jabber-chat-print-url'). The functions in `jabber-chat-printers' are called in order, with the entire `' stanza as argument. As described in the docstring of `jabber-chat-printers', these functions are run in one of two modes: `printp', in which they are supposed to return true if they would print anything, and `insert', in which they are supposed to actually print something, if appropriate, using the function `insert'. For MUC, the functions in `jabber-muc-printers' are prepended to those in `jabber-chat-printers'. Body printers are a subgroup of chat printers. They are exclusive; only one of them applies to any given message. The idea is that "higher-quality" parts of the message override pieces included for backwards compatibility. Included are `jabber-muc-print-invite' and `jabber-chat-normal-body'; functions for XHTML-IM and PGP encrypted messages may be written in the future. The functions in `jabber-body-printers' are called in order until one of them returns non-nil.  File: jabber.info, Node: Stanza chains, Prev: Chat printers, Up: Hacking and extending 16.8 Stanza chains ================== If you really need to get under the skin of jabber.el, you can add functions to the lists `jabber-message-chain', `jabber-iq-chain' and `jabber-presence-chain'. The functions in these lists will be called in order when an XML stanza of the corresponding type arrives, with the connection object and the entire XML stanza passed as arguments. Earlier functions can modify the stanza to change the behaviour of downstream functions, but remember: with great power comes great responsibility.  File: jabber.info, Node: Protocol support, Next: Concept index, Prev: Hacking and extending, Up: Top Appendix A Protocol support *************************** These are the protocols currently supported (in full or partially) by jabber.el. * Menu: * RFC 3920:: XMPP-CORE * RFC 3921:: XMPP-IM * XEP-0004:: Data Forms * XEP-0012:: Last Activity * XEP-0020:: Feature Negotiation * XEP-0022:: Message Events * XEP-0030:: Service Discovery * XEP-0045:: Multi-User Chat * XEP-0049:: Private XML Storage * XEP-0050:: Ad-Hoc Commands * XEP-0054:: vcard-temp * XEP-0055:: Jabber Search * XEP-0065:: SOCKS5 Bytestreams * XEP-0066:: Out of Band Data * XEP-0068:: Field Standardization for Data Forms * XEP-0077:: In-Band Registration * XEP-0078:: Non-SASL Authentication * XEP-0082:: Jabber Date and Time Profiles * XEP-0085:: Chat State Notifications * XEP-0086:: Error Condition Mappings * XEP-0090:: Entity Time * XEP-0091:: Delayed Delivery * XEP-0092:: Software Version * XEP-0095:: Stream Initiation * XEP-0096:: File Transfer * XEP-0146:: Remote Controlling Clients * XEP-0153:: vCard-Based Avatars  File: jabber.info, Node: RFC 3920, Next: RFC 3921, Prev: Protocol support, Up: Protocol support A.1 RFC 3920 (XMPP-CORE) ======================== Most of RFC 3920 is supported, with the following exceptions. SASL is supported only when an external SASL library from FLIM or Gnus is present. As SASL is an essential part to XMPP, jabber.el will send pre-XMPP stream headers if it is not available. None of the stringprep profiles are implemented. jabber.el changes JIDs to lowercase internally; that's all. jabber.el doesn't interpret namespace prefixes. The `xml:lang' attribute is neither interpreted nor generated. SRV records are used if a modern version of `dns.el' is installed.  File: jabber.info, Node: RFC 3921, Next: XEP-0004, Prev: RFC 3920, Up: Protocol support A.2 RFC 3921 (XMPP-IM) ====================== Most of RFC 3921 is supported, with the following exceptions. Messages of type "headline" are not treated in any special way. The `' element is not used or generated. Sending "directed presence" is supported; however, presence stanzas received from contacts not in roster are ignored. Privacy lists are not supported at all. jabber.el doesn't support XMPP-E2E or "im:" CPIM URIs.  File: jabber.info, Node: XEP-0004, Next: XEP-0012, Prev: RFC 3921, Up: Protocol support A.3 XEP-0004 (Data Forms) ========================= XEP-0004 support is good enough for many purposes. Limitations are the following. Forms in incoming messages are not interpreted. See each specific protocol for whether forms are accepted in that context. "Cancel" messages are probably not consistently generated when they should be. This is partly a paradigm clash, as jabber.el doesn't use modal dialog boxes but buffers which can easily be buried. `' elements are not enforced. The field types "jid-single", "jid-multi" and "list-multi" are not implemented, due to programmer laziness. Let us know if you need them.  File: jabber.info, Node: XEP-0012, Next: XEP-0020, Prev: XEP-0004, Up: Protocol support A.4 XEP-0012 (Last Activity) ============================ jabber.el can generate all three query types described in the protocol. However, it does not answer to such requests.  File: jabber.info, Node: XEP-0020, Next: XEP-0022, Prev: XEP-0012, Up: Protocol support A.5 XEP-0020 (Feature Negotiation) ================================== There are no known limitations or bugs in XEP-0020 support.  File: jabber.info, Node: XEP-0022, Next: XEP-0030, Prev: XEP-0020, Up: Protocol support A.6 XEP-0022 (Message Events) ============================= jabber.el understands all four specified kinds of message events (offline, delivered, displayed, and composing) and by default requests all of them. It also reports those three events that make sense for clients.  File: jabber.info, Node: XEP-0030, Next: XEP-0045, Prev: XEP-0022, Up: Protocol support A.7 XEP-0030 (Service Discovery) ================================ Service discovery is supported, both as client and server. When used in the code, service discovery results are cached indefinitely.  File: jabber.info, Node: XEP-0045, Next: XEP-0049, Prev: XEP-0030, Up: Protocol support A.8 XEP-0045 (Multi-User Chat) ============================== jabber.el supports parts of XEP-0045. Entering, leaving and chatting work. So do invitations and private messages. Room configuration is supported. Changing roles of participants (basic moderation) is implemented, as is changing affiliations, but requesting affiliation lists is not yet supported.  File: jabber.info, Node: XEP-0049, Next: XEP-0050, Prev: XEP-0045, Up: Protocol support A.9 XEP-0049 (Private XML Storage) ================================== jabber.el contains an implementation of XEP-0049; however it is not used for anything right now.  File: jabber.info, Node: XEP-0050, Next: XEP-0054, Prev: XEP-0049, Up: Protocol support A.10 XEP-0050 (Ad-Hoc Commands) =============================== jabber.el is probably the first implementation of XEP-0050 (see post on jdev from 2004-03-10 (http://article.gmane.org/gmane.network.jabber.devel/21413)). Both the client and server parts are supported.  File: jabber.info, Node: XEP-0054, Next: XEP-0055, Prev: XEP-0050, Up: Protocol support A.11 XEP-0054 (vcard-temp) ========================== Both displaying other users' vCards and editing your own vCard are supported. The implementation tries to follow the schema in the XEP accurately.  File: jabber.info, Node: XEP-0055, Next: XEP-0065, Prev: XEP-0054, Up: Protocol support A.12 XEP-0055 (Jabber Search) ============================= XEP-0055 is supported, both with traditional fields and with Data Forms (*note XEP-0004::). As the traditional fields specified by the XEP is a subset of those allowed in XEP-0077, handling of those two form types are merged. *Note XEP-0077::.  File: jabber.info, Node: XEP-0065, Next: XEP-0066, Prev: XEP-0055, Up: Protocol support A.13 XEP-0065 (SOCKS5 Bytestreams) ================================== XEP-0065 is supported. Currently jabber.el cannot act as a server, not even on on Emacsen that support server sockets (GNU Emacs 22 and up). Therefore it relies on proxies. Proxies have to be entered and queried manually. Psi's "fast mode" (`http://delta.affinix.com/specs/stream.html'), which gives greater flexibility with regards to NAT, is not implemented.  File: jabber.info, Node: XEP-0066, Next: XEP-0068, Prev: XEP-0065, Up: Protocol support A.14 XEP-0066 (Out of Band Data) ================================ jabber.el will display URLs sent in message stanzas qualified by the `jabber:x:oob' namespace, as described in this XEP. Sending such URLs or doing anything with iq stanzas (using the `jabber:iq:oob' namespace) is not supported.  File: jabber.info, Node: XEP-0068, Next: XEP-0077, Prev: XEP-0066, Up: Protocol support A.15 XEP-0068 (Field Standardization for Data Forms) ==================================================== XEP-0068 is only used in the context of creating a new Jabber account, to prefill the username field of the registration form.  File: jabber.info, Node: XEP-0077, Next: XEP-0078, Prev: XEP-0068, Up: Protocol support A.16 XEP-0077 (In-Band Registration) ==================================== In-band registration is supported for all purposes. That means registering a new Jabber account, changing Jabber password, removing a Jabber account, registering with a service, and cancelling registration to a service. Data forms are supported as well. URL redirections are not. jabber.el will not prevent or alert a user trying to change a password over an unencrypted connection.  File: jabber.info, Node: XEP-0078, Next: XEP-0082, Prev: XEP-0077, Up: Protocol support A.17 XEP-0078 (Non-SASL Authentication) ======================================= Non-SASL authentication is supported, both plaintext and digest. Digest is preferred, and a warning is displayed to the user if only plaintext is available.  File: jabber.info, Node: XEP-0082, Next: XEP-0085, Prev: XEP-0078, Up: Protocol support A.18 XEP-0082 (Jabber Date and Time Profiles) ============================================= The DateTime profile of XEP-0082 is supported. Currently this is only used for file transfer.  File: jabber.info, Node: XEP-0085, Next: XEP-0086, Prev: XEP-0082, Up: Protocol support A.19 XEP-0085 (Chat State Notifications) ======================================== XEP-0085 is partially supported. Currently only active/composing notifications are _sent_ though all five notifications are handled on receipt.  File: jabber.info, Node: XEP-0086, Next: XEP-0090, Prev: XEP-0085, Up: Protocol support A.20 XEP-0086 (Error Condition Mappings) ======================================== Legacy errors are interpreted, but never generated. XMPP style error messages take precedence when errors are reported to the user.  File: jabber.info, Node: XEP-0090, Next: XEP-0091, Prev: XEP-0086, Up: Protocol support A.21 XEP-0090 (Entity Time) =========================== jabber.el can query other entities for their time, and return the current time to those who ask.  File: jabber.info, Node: XEP-0091, Next: XEP-0092, Prev: XEP-0090, Up: Protocol support A.22 XEP-0091 (Delayed Delivery) ================================ The time specified on delayed incoming messages is interpreted, and displayed in chat buffers instead of the current time.  File: jabber.info, Node: XEP-0092, Next: XEP-0095, Prev: XEP-0091, Up: Protocol support A.23 XEP-0092 (Software Version) ================================ The user can request the version of any entity. jabber.el answers version requests to anyone, giving "jabber.el" as name, and the Emacs version as OS.  File: jabber.info, Node: XEP-0095, Next: XEP-0096, Prev: XEP-0092, Up: Protocol support A.24 XEP-0095 (Stream Initiation) ================================= XEP-0095 is supported, both incoming and outgoing, except that jabber.el doesn't check service discovery results before sending a stream initiation request.  File: jabber.info, Node: XEP-0096, Next: XEP-0146, Prev: XEP-0095, Up: Protocol support A.25 XEP-0096 (File Transfer) ============================= Both sending and receiving files is supported. If a suitable program is found, MD5 hashes of outgoing files are calculated and sent. However, hashes of received files are not checked. Ranged transfers are not supported. In-band bytestreams are not yet supported, even though XEP-0096 requires them.  File: jabber.info, Node: XEP-0146, Next: XEP-0153, Prev: XEP-0096, Up: Protocol support A.26 XEP-0146 (Remote Controlling Clients) ========================================== The "set-status" command in XEP-0146 is supported.  File: jabber.info, Node: XEP-0153, Prev: XEP-0146, Up: Protocol support A.27 XEP-0153 (vCard-Based Avatars) =================================== vCard-based avatars are supported, both publishing and displaying. The pixel size limits on avatars are not enforced.  File: jabber.info, Node: Concept index, Next: Function index, Prev: Protocol support, Up: Top Concept index ************* [index] * Menu: * account object: Connection object. (line 6) * Account removal: Your home server. (line 6) * Activity: Tracking activity. (line 6) * Ad-Hoc Commands: Ad-Hoc Commands. (line 6) * Affiliations, MUC: MUC Administration. (line 37) * AIM transport: Transports. (line 6) * Alert hooks: Customizing alerts. (line 6) * Alerts: Standard alerts. (line 6) * Autoanswerer: Standard alerts. (line 58) * autoaway: Autoaway. (line 6) * Autojoin chat rooms: Configuration. (line 6) * Automatic reconnection: Reconnecting. (line 6) * avatars: Avatars. (line 6) * Backlog: Message history. (line 6) * Banning, MUC: MUC Administration. (line 37) * Body printers: Chat printers. (line 6) * Bookmarks, MUC: Configuration. (line 6) * Browse buffers: Services. (line 6) * browser integration: XMPP URIs. (line 6) * Browsing: Browsing. (line 6) * Changing nickname: Groupchat. (line 9) * Changing password: Your home server. (line 6) * Chat buffer: Customizing the chat buffer. (line 6) * Chat printers: Chat printers. (line 6) * Chatrooms: Groupchat. (line 6) * Chatting: Chatting. (line 6) * Composing: Typing notifications. (line 13) * composing messages: Composing messages. (line 6) * Connecting: Connecting. (line 6) * connection object: Connection object. (line 6) * Customization: Customization. (line 6) * Default MUC nickname: Configuration. (line 6) * Delivered: Typing notifications. (line 13) * Detecting lost connections: Keepalive. (line 6) * directed presence: Directed presence. (line 6) * Displayed: Typing notifications. (line 13) * Export roster: Roster import and export. (line 6) * Faces, chat buffer: Customizing the chat buffer. (line 6) * Festival speech synthesis: Standard alerts. (line 55) * File transfer: File transfer. (line 6) * file transfer proxy: Sending files. (line 6) * Filling long lines in chat buffer: Customizing the chat buffer. (line 61) * flyspell: Spell checking. (line 6) * FSM: Connection object. (line 6) * Gateways: Transports. (line 6) * Google Talk: Account settings. (line 41) * Groupchat: Groupchat. (line 6) * Groupchat completion: Groupchat. (line 33) * Header line of chat buffers: Customizing the chat buffer. (line 55) * Hiding offline contacts: Roster buffer. (line 33) * History: Message history. (line 6) * History file rotation: Message history. (line 27) * ICQ transport: Transports. (line 6) * idle: Autoaway. (line 6) * idle time, query: Time queries. (line 13) * Import roster: Roster import and export. (line 6) * Invitations: Invitations. (line 6) * JID: Account settings. (line 6) * Joining a groupchat: Groupchat. (line 9) * Keepalive: Keepalive. (line 6) * Key bindings: Roster buffer. (line 6) * Kicking, MUC: MUC Administration. (line 13) * last online: Time queries. (line 10) * libnotify: Standard alerts. (line 52) * links: XMPP URIs. (line 6) * Menus <1>: Menu. (line 6) * Menus: Roster buffer. (line 6) * message composition: Composing messages. (line 6) * Modeline: Modeline status. (line 6) * Moderator, MUC: MUC Administration. (line 13) * Mozilla integration: XMPP URIs. (line 6) * MSN transport: Transports. (line 6) * MUC: Groupchat. (line 6) * Network server: Account settings. (line 6) * Nick completion in groupchat: Groupchat. (line 33) * Nickname, changing: Groupchat. (line 9) * notification-daemon: Standard alerts. (line 52) * Offline contacts, hiding: Roster buffer. (line 33) * Online notifications: Watch buddies. (line 6) * OSD: Standard alerts. (line 50) * Password: Account settings. (line 6) * Password change: Your home server. (line 6) * Personal information: Personal information. (line 6) * Presence: Presence. (line 6) * Presence subscription: Presence subscription. (line 6) * Priority: Resources and priority. (line 6) * Private MUC messages: Private messages. (line 6) * proxy, file transfer: Sending files. (line 6) * Query groupchat: Groupchat. (line 16) * Rare timestamps: Customizing the chat buffer. (line 49) * Ratpoison window manager: Standard alerts. (line 36) * Reconnect: Reconnecting. (line 6) * Registering an account: Registering an account. (line 6) * Registration: Registration. (line 6) * Removing an account: Your home server. (line 6) * Resource <1>: Account settings. (line 6) * Resource: Resources and priority. (line 6) * Roles, MUC: MUC Administration. (line 13) * Roster buffer, basics: Roster buffer. (line 6) * Roster buffer, customizing: Customizing the roster buffer. (line 6) * Rotation of history files: Message history. (line 27) * Sawfish window manager: Standard alerts. (line 41) * Screen terminal manager: Standard alerts. (line 33) * Scroll: Standard alerts. (line 6) * Scroll chat buffers: Standard alerts. (line 62) * Search: Search. (line 6) * send directed presence: Directed presence. (line 6) * Sending files: File transfer. (line 6) * Sending presence: Presence. (line 6) * Service discovery: Service discovery. (line 6) * Sorting the roster: Customizing the roster buffer. (line 6) * Sound effects: Standard alerts. (line 25) * Speech synthesis, Festival: Standard alerts. (line 55) * Spell checking: Spell checking. (line 6) * Subscribing to someone's presence: Presence subscription. (line 6) * Supported protocols: Protocol support. (line 6) * time query: Time queries. (line 6) * Timestamp format: Customizing the chat buffer. (line 38) * Timestamps: Customizing the chat buffer. (line 6) * Topic, MUC: Groupchat. (line 41) * Transports: Transports. (line 6) * Truncate: Message history. (line 45) * Truncation: Message history. (line 45) * uptime, query: Time queries. (line 13) * URIs: XMPP URIs. (line 6) * URLs: XMPP URIs. (line 6) * Username: Account settings. (line 6) * vCard: Personal information. (line 6) * Voice, MUC: MUC Administration. (line 13) * Watch: Watch buddies. (line 6) * web browser integration: XMPP URIs. (line 6) * Whitespace pings: Keepalive. (line 22) * Window manager, Ratpoison: Standard alerts. (line 36) * Window manager, Sawfish: Standard alerts. (line 41) * Window manager, wmii: Standard alerts. (line 44) * wmii window manager: Standard alerts. (line 44) * XEP-0065 proxy: Sending files. (line 6) * xmessage: Standard alerts. (line 46) * XML log: Debug options. (line 9) * XML representation: XML representation. (line 6) * xmpp: links: XMPP URIs. (line 6) * xprintidle: Autoaway. (line 6)  File: jabber.info, Node: Function index, Next: Variable index, Prev: Concept index, Up: Top Function index ************** [index] * Menu: * define-jabber-alert: Customizing alerts. (line 6) * jabber-activity-mode: Tracking activity. (line 6) * jabber-ahc-execute-command: Ad-Hoc Commands. (line 6) * jabber-ahc-get-list: Ad-Hoc Commands. (line 6) * jabber-chat-display-more-backlog: Message history. (line 22) * jabber-chat-with: Chatting. (line 6) * jabber-compose: Composing messages. (line 6) * jabber-connect: Connecting. (line 6) * jabber-connect-all: Connecting. (line 6) * jabber-connection-bare-jid: Connection object. (line 26) * jabber-connection-jid: Connection object. (line 22) * jabber-customize: Customization. (line 6) * jabber-disco-get-info: Requesting info. (line 14) * jabber-disco-get-info-immediately: Requesting info. (line 46) * jabber-disco-get-items: Requesting info. (line 29) * jabber-disco-get-items-immediately: Requesting info. (line 51) * jabber-disconnect: Connecting. (line 6) * jabber-disconnect-one: Connecting. (line 6) * jabber-display-roster: Roster buffer. (line 23) * jabber-edit-bookmarks: Configuration. (line 6) * jabber-export-roster: Roster import and export. (line 6) * jabber-ft-send: Sending files. (line 17) * jabber-get-browse: Browsing. (line 6) * jabber-get-disco-info: Service discovery. (line 6) * jabber-get-disco-items: Service discovery. (line 6) * jabber-get-idle-time: Time queries. (line 13) * jabber-get-last-online: Time queries. (line 10) * jabber-get-register: Registration. (line 6) * jabber-get-search: Search. (line 6) * jabber-get-time: Time queries. (line 6) * jabber-groupchat-get-config: Groupchat. (line 46) * jabber-groupchat-join: Groupchat. (line 9) * jabber-groupchat-leave: Groupchat. (line 44) * jabber-handle-uri: XMPP URIs. (line 6) * jabber-import-roster: Roster import and export. (line 6) * jabber-info-default-message: Info alerts. (line 6) * jabber-keepalive-start: Keepalive. (line 45) * jabber-keepalive-stop: Keepalive. (line 45) * jabber-menu: Menu. (line 13) * jabber-message-default-message: Message alerts. (line 6) * jabber-mode-line-mode: Modeline status. (line 6) * jabber-muc-autojoin: Configuration. (line 6) * jabber-muc-default-message: MUC alerts. (line 6) * jabber-muc-invite: Invitations. (line 6) * jabber-muc-names: Groupchat. (line 50) * jabber-muc-private: Private messages. (line 6) * jabber-muc-set-affiliation: MUC Administration. (line 37) * jabber-muc-set-role: MUC Administration. (line 13) * jabber-muc-set-topic: Groupchat. (line 41) * jabber-my-jid-p: Providing info. (line 24) * jabber-presence-default-message: Presence alerts. (line 6) * jabber-process-data: Sending new requests. (line 20) * jabber-process-iq <1>: Sending new requests. (line 6) * jabber-process-iq: Listening for new requests. (line 6) * jabber-report-success: Sending new requests. (line 20) * jabber-send-default-presence: Presence. (line 6) * jabber-send-directed-presence: Directed presence. (line 6) * jabber-send-iq <1>: Sending new requests. (line 6) * jabber-send-iq: Listening for new requests. (line 6) * jabber-send-presence: Presence. (line 6) * jabber-send-sexp: XML representation. (line 32) * jabber-send-subscription-request: Presence subscription. (line 6) * jabber-sexp2xml: XML representation. (line 26) * jabber-signal-error: Listening for new requests. (line 6) * jabber-socks5-query-all-proxies: Sending files. (line 13) * jabber-truncate-chat: Message history. (line 6) * jabber-truncate-muc: Message history. (line 6) * jabber-truncate-top: Message history. (line 6) * jabber-vcard-edit: Personal information. (line 6) * jabber-vcard-get: Personal information. (line 6) * jabber-watch-add: Watch buddies. (line 6) * jabber-watch-remove: Watch buddies. (line 6) * jabber-whitespace-ping-start: Keepalive. (line 29) * jabber-whitespace-ping-stop: Keepalive. (line 29)  File: jabber.info, Node: Variable index, Prev: Function index, Up: Top Variable index ************** [index] * Menu: * jabber-account-list: Account settings. (line 6) * jabber-activity-count-in-title: Tracking activity. (line 6) * jabber-activity-count-in-title-format: Tracking activity. (line 6) * jabber-activity-make-strings: Tracking activity. (line 6) * jabber-activity-query-unread: Tracking activity. (line 6) * jabber-advertised-features: Providing info. (line 9) * jabber-alert-info-message-function: Info alerts. (line 6) * jabber-alert-message-function: Message alerts. (line 6) * jabber-alert-muc-function: MUC alerts. (line 6) * jabber-alert-presence-message-function: Presence alerts. (line 6) * jabber-auto-reconnect: Reconnecting. (line 6) * jabber-autoaway-method: Autoaway. (line 6) * jabber-avatar-cache-directory: Avatars. (line 6) * jabber-backlog-days: Message history. (line 6) * jabber-backlog-number: Message history. (line 6) * jabber-body-printers: Chat printers. (line 6) * jabber-browse-mode-hook: Hooks. (line 32) * jabber-chat-buffer-show-avatar: Avatars. (line 6) * jabber-chat-delayed-time-format: Customizing the chat buffer. (line 42) * jabber-chat-fill-long-lines: Customizing the chat buffer. (line 61) * jabber-chat-foreign-prompt-format: Customizing the chat buffer. (line 16) * jabber-chat-header-line-format: Customizing the chat buffer. (line 55) * jabber-chat-local-prompt-format: Customizing the chat buffer. (line 16) * jabber-chat-mode-hook: Hooks. (line 29) * jabber-chat-printers: Chat printers. (line 6) * jabber-chat-prompt-foreign: Customizing the chat buffer. (line 13) * jabber-chat-prompt-local: Customizing the chat buffer. (line 13) * jabber-chat-text-foreign: Customizing the chat buffer. (line 10) * jabber-chat-text-local: Customizing the chat buffer. (line 10) * jabber-chat-time-format: Customizing the chat buffer. (line 38) * jabber-chatstates-confirm: Typing notifications. (line 40) * jabber-debug-keep-process-buffers: Debug options. (line 13) * jabber-debug-log-xml: Debug options. (line 9) * jabber-default-priority: Presence. (line 6) * jabber-default-show: Presence. (line 6) * jabber-default-status: Presence. (line 6) * jabber-disco-info-nodes: Providing info. (line 12) * jabber-disco-items-nodes: Providing info. (line 12) * jabber-display-menu: Menu. (line 6) * jabber-events-confirm-composing: Typing notifications. (line 13) * jabber-events-confirm-delivered: Typing notifications. (line 13) * jabber-events-confirm-displayed: Typing notifications. (line 13) * jabber-events-request-these: Typing notifications. (line 13) * jabber-global-history-filename: Message history. (line 6) * jabber-history-dir: Message history. (line 6) * jabber-history-enable-rotation: Message history. (line 6) * jabber-history-enabled: Message history. (line 6) * jabber-history-size-limit: Message history. (line 6) * jabber-iq-chain: Stanza chains. (line 6) * jabber-iq-get-xmlns-alist: Listening for new requests. (line 6) * jabber-iq-set-xmlns-alist: Listening for new requests. (line 6) * jabber-jid-obarray: JID symbols. (line 6) * jabber-keepalive-interval: Keepalive. (line 49) * jabber-keepalive-timeout: Keepalive. (line 49) * jabber-log-lines-to-keep: Message history. (line 6) * jabber-lost-connection-hooks: Hooks. (line 14) * jabber-message-alert-same-buffer: Message alerts. (line 23) * jabber-message-chain: Stanza chains. (line 6) * jabber-mode-line-compact: Modeline status. (line 6) * jabber-mode-line-mode: Modeline status. (line 6) * jabber-muc-alert-self: MUC alerts. (line 6) * jabber-muc-autojoin: Configuration. (line 6) * jabber-muc-completion-delimiter: Groupchat. (line 33) * jabber-muc-default-nicknames: Configuration. (line 6) * jabber-muc-disable-disco-check: Groupchat. (line 16) * jabber-muc-header-line-format: Customizing the chat buffer. (line 55) * jabber-muc-looks-personaling-symbols: Groupchat. (line 33) * jabber-muc-printers: Chat printers. (line 6) * jabber-post-connect-hooks: Hooks. (line 8) * jabber-post-disconnect-hook: Hooks. (line 25) * jabber-pre-disconnect-hook: Hooks. (line 20) * jabber-presence-chain: Stanza chains. (line 6) * jabber-print-rare-time: Customizing the chat buffer. (line 49) * jabber-rare-time-format: Customizing the chat buffer. (line 49) * jabber-resource-line-format: Customizing the roster buffer. (line 54) * jabber-roster-buffer: Customizing the roster buffer. (line 59) * jabber-roster-line-format: Customizing the roster buffer. (line 18) * jabber-roster-mode-hook: Hooks. (line 35) * jabber-roster-show-bindings <1>: Customizing the roster buffer. (line 63) * jabber-roster-show-bindings: Roster buffer. (line 20) * jabber-roster-sort-functions: Customizing the roster buffer. (line 6) * jabber-show-offline-contacts: Roster buffer. (line 33) * jabber-show-resources: Customizing the roster buffer. (line 14) * jabber-socks5-proxies: Sending files. (line 13) * jabber-sort-order: Customizing the roster buffer. (line 10) * jabber-use-global-history: Message history. (line 6) * jabber-vcard-avatars-publish: Avatars. (line 6) * jabber-vcard-avatars-retrieve: Avatars. (line 6) * jabber-whitespace-ping-interval: Keepalive. (line 33) * jabber-xmessage-timeout: Standard alerts. (line 46)  Tag Table: Node: Top514 Node: Introduction1345 Node: Contact2200 Node: Basic operation2895 Node: Do you have a Jabber account?3790 Node: Registering an account4409 Node: Connecting5106 Node: Chatting6181 Node: Presence7600 Node: Resources and priority9758 Node: Directed presence11488 Node: Presence subscription12028 Ref: Presence subscription-Footnote-113591 Node: Roster buffer13686 Ref: Roster buffer-Footnote-115419 Node: Groupchat15500 Node: Configuration18238 Node: Invitations19663 Node: Private messages20341 Node: MUC Administration20964 Node: Composing messages22567 Node: File transfer23192 Ref: File transfer-Footnote-123946 Node: Receiving files24112 Node: Sending files25476 Ref: Sending files-Footnote-127102 Node: Services27262 Node: Commands28166 Node: Registration28758 Node: Search29378 Node: Ad-Hoc Commands29763 Ref: Ad-Hoc Commands-Footnote-131259 Ref: Ad-Hoc Commands-Footnote-231366 Node: Service discovery31502 Node: Browsing32703 Node: Your home server33063 Node: Transports33421 Ref: Transports-Footnote-135823 Node: User directories35899 Node: MUC services36302 Node: Personal information36731 Ref: Personal information-Footnote-137577 Node: Avatars37603 Node: Time queries39151 Node: Useful features40018 Node: Autoaway40395 Ref: Autoaway-Footnote-142556 Node: Modeline status42623 Node: Keepalive43335 Node: Reconnecting45368 Node: Tracking activity46077 Node: Watch buddies47757 Node: Spell checking48454 Node: Message history48938 Node: Typing notifications51557 Node: Roster import and export53403 Node: XMPP URIs54353 Node: Customization56712 Node: Account settings57167 Ref: Account settings-Footnote-159164 Node: Menu59221 Node: Customizing the roster buffer59834 Node: Customizing the chat buffer62022 Node: Customizing alerts64488 Node: Standard alerts66654 Ref: Standard alerts-Footnote-170148 Ref: Standard alerts-Footnote-270199 Ref: Standard alerts-Footnote-370248 Ref: Standard alerts-Footnote-470387 Node: Presence alerts70446 Node: Message alerts71848 Ref: Message alerts-Footnote-172961 Node: MUC alerts73064 Node: Info alerts73944 Node: Hooks74474 Node: Debug options75802 Node: Hacking and extending76522 Node: Connection object77122 Ref: Connection object-Footnote-178443 Node: XML representation78575 Node: JID symbols80086 Node: Listening for new requests81501 Node: Sending new requests82753 Node: Extending service discovery85033 Node: Providing info85483 Node: Requesting info86976 Node: Chat printers89476 Node: Stanza chains90899 Node: Protocol support91523 Node: RFC 392093140 Node: RFC 392193855 Node: XEP-000494407 Node: XEP-001295156 Node: XEP-002095429 Node: XEP-002295656 Node: XEP-003096027 Node: XEP-004596324 Node: XEP-004996785 Node: XEP-005097049 Node: XEP-005497414 Node: XEP-005597713 Node: XEP-006598116 Node: XEP-006698650 Node: XEP-006899043 Node: XEP-007799373 Node: XEP-007899934 Node: XEP-0082100268 Node: XEP-0085100552 Node: XEP-0086100875 Node: XEP-0090101187 Node: XEP-0091101437 Node: XEP-0092101723 Node: XEP-0095102038 Node: XEP-0096102360 Node: XEP-0146102820 Node: XEP-0153103054 Node: Concept index103325 Node: Function index114934 Node: Variable index120893  End Tag Table