# HG changeset patch # User Mikael Berthe # Date 1122214433 -3600 # Node ID 33b8e801ffa65a7d441e017022a76cccc17e9e27 # Parent 913915140ad26063607c6d5153b034c223b356ce# Parent 65aa055205563d7ec6b949ed2d900d14dbfea8c2 Merge changeset 315 (65aa05520556) diff -r 65aa05520556 -r 33b8e801ffa6 .hgtags --- a/.hgtags Fri Jul 15 10:56:15 2005 +0100 +++ b/.hgtags Sun Jul 24 15:13:53 2005 +0100 @@ -2,3 +2,4 @@ ff9ba796cabba5547b33b096ac48027cb5cc2ccd 0.6.1 bb71b5707b00e6a8cd028e350a33c455692723a5 0.6.2 70914672c8e71ee0e99ecb1f45800216ec9efebe 0.6.3 +74cf831b8117f39465d10fbe2bf766a46d60955a 0.6.4 diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/ChangeLog --- a/mcabber/ChangeLog Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/ChangeLog Sun Jul 24 15:13:53 2005 +0100 @@ -1,10 +1,27 @@ -mcabber (0.6.4-dev) +mcabber (0.6.5-dev) - * One Ctrl-C does not terminate mcabber anymore (the 2nd Ctrl-C do), but - abort current completion + -- Mikael, ? +mcabber (0.6.4) + + * Configuration file format change (see NEWS file) + Aliases & key bindings can be put in the config. file + * Enable /set command + * [FIX] Convert status messages to/from UTF-8 + * The /status command can specify a status message + * Display the buddy status message when a buddy connects/changes his status + * New autoaway feature (see sample config. file) + * New "/roster alternate". Jumps to the last buddy window left in chat mode + * Handle "error" message type + * One Ctrl-C does not terminate mcabber anymore (the 2nd Ctrl-C do), but + leaves multi-line message mode and aborts current completion + * Add a sample script to handle events (currently, it plays a sounds when + a message is received) + + -- Mikael, 2005-07-20 + mcabber (0.6.3) * Fix interactive password crash diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/NEWS --- a/mcabber/NEWS Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/NEWS Sun Jul 24 15:13:53 2005 +0100 @@ -1,3 +1,10 @@ +mcabber (0.6.4) + + * The configuration file format has changed. Options need to be set using + the "set" keywords. The sample config. file has been updated. + + -- Mikael, 2005-07-18 + mcabber (0.6.2) * Support for old style (i.e. < 0.6.1) history logfiles has been removed. diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/README --- a/mcabber/README Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/README Sun Jul 24 15:13:53 2005 +0100 @@ -1,12 +1,15 @@ -Well, the documentation is missing yet, but... + Hello, and thanks for trying mcabber. -!!!!!! SEE mcabberrc.example !!!!!! +For installation instruction, have a look at the INSTALL file. -A configuration file is necessary. -Its name is $HOME/.mcabber/mcabberrc (or $HOME/.mcabberrc). -Please see the sample config file! +A configuration file is necessary to start mcabber. Its name is +$HOME/.mcabber/mcabberrc (or $HOME/.mcabberrc). -You can use the -f option to specify another configuration file. +A sample configuration file, "mcabberrc.example", is provided in this +directory. Copy it and modify it to fit your needs. + + +You can use mcabber "-f" option to specify another configuration file. This software is under development, please give me some feedback (and some diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/TODO --- a/mcabber/TODO Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/TODO Sun Jul 24 15:13:53 2005 +0100 @@ -5,7 +5,10 @@ TODO: +* More events +* Add debian/ directory * Improve debug logging system +* Implement automatic reconnection after network failure * Presence notification is always accepted. We should ask... * UTF-8 support (Can somebody help me?) * Display status / chat mode @@ -17,13 +20,9 @@ * Create .mcabber and .mcabber/histo dirs if needed. Or maybe not. However it could be a good idea to check the permissions. * Publish personal information -* Handle message type "error" * Show status changes in buddy window (if open)? * Options completion * Configuration file parsing: parse as commands (set, alias, bind) -* Auto away -* Add a sample script for the events command -* Make first Ctrl-C leave multi-line mode * Keep track of buddy resources. Ex.: - buddy A connects with resource r1 - buddy A connects with resource r2 @@ -49,7 +48,6 @@ - /auth request|send [jid] - /search |name (server search) - - status status Message - /help - /rawxml... diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/configure.ac --- a/mcabber/configure.ac Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/configure.ac Sun Jul 24 15:13:53 2005 +0100 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([mcabber],[0.6.4-dev],[mcabber@lilotux.net]) +AC_INIT([mcabber],[0.6.5-dev],[mcabber@lilotux.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([src]) AM_CONFIG_HEADER(config.h) diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/contrib/eventcmd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/contrib/eventcmd Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,33 @@ +#! /bin/sh +# +# Sample events script for mcabber +# Plays a sound when receiving a message +# +# To use this script, set the "events_command" option to the path of +# the script (see the mcabberrc.example file for an example) +# +# MiKael, 2005-07-15 + +# The following sound comes with the gtkboard package, +# you can modify this line to play another one... +CMD_MSG_IN="/usr/bin/play /usr/share/sounds/gtkboard/machine_move.ogg" + +event=$1 +arg1=$2 +arg2=$3 + +if [ $event == "MSG" ]; then + case "$arg1" in + IN) + # Incoming message from buddy $arg2 + $CMD_MSG_IN > /dev/null 2>&1 + ;; + OUT) + # Outgoing message for buddy $arg2 + ;; + esac +elif [ $event == "STATUS" ]; then + # Buddy $arg2 status is $arg1 (_, O, I, F, D, N, A) + echo > /dev/null +fi + diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/changelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/changelog Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,12 @@ +mcabber (0.6.4-2) unstable; urgency=low + + * Improve Debian package, with some help from Benjamin Drieu + + -- Mikael BERTHE Sat, 23 Jul 2005 15:26:58 +0200 + +mcabber (0.6.4-1) unstable; urgency=low + + * Initial release + + -- Mikael BERTHE Thu, 21 Jul 2005 20:32:41 +0200 + diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/compat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/compat Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,1 @@ +4 diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/control Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,16 @@ +Source: mcabber +Section: net +Priority: optional +Maintainer: Mikael BERTHE +Build-Depends: debhelper (>= 4.0.0), autotools-dev, libglib2.0-dev, libncurses5-dev, libssl-dev +Standards-Version: 3.6.1 + +Package: mcabber +Section: net +Priority: optional +Architecture: any +Depends: ${shlibs:Depends} +Description: Small Jabber console client + MCabber is a Jabber text-mode client, which includes features such as + SSL support, history logging, commands completion, and external actions + triggers. diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/copyright --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/copyright Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,27 @@ +This package was debianized by Mikael BERTHE on +Thu, 21 Jul 2005 20:32:41 +0200. + +It was downloaded from: http://www.lilotux.net/~mikael/mcabber/ + +Copyright Holder: Mikael BERTHE + +License: + + This package 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 package 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 package; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + +On Debian systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. + diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/docs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/docs Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,6 @@ +AUTHORS +NEWS +README +TODO +doc/mcabber.1.txt +doc/mcabber.1.html diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/mcabber.doc-base --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/mcabber.doc-base Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,15 @@ +Document: mcabber +Title: Debian mcabber Manual +Author: Mikael BERTHE +Abstract: This manual describes what mcabber is + and how it can be used. +Section: Apps/Net + +#Format: text +#Files: /usr/share/doc/mcabber/mcabber.1.txt.gz + +Format: HTML +Index: /usr/share/doc/mcabber/mcabber.1.html +Files: /usr/share/doc/mcabber/mcabber.1.html + + diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/menu --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/menu Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,2 @@ +?package(mcabber):needs="text" section="Apps/Net"\ + title="MCabber" command="/usr/bin/mcabber" diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/rules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/rules Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,107 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif + +config.status: configure + dh_testdir + # Add here commands to configure the package. + CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info + + +build: build-stamp + +build-stamp: config.status + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + #docbook-to-man debian/mcabber.sgml > mcabber.1 + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) distclean +ifneq "$(wildcard /usr/share/misc/config.sub)" "" + cp -f /usr/share/misc/config.sub config.sub +endif +ifneq "$(wildcard /usr/share/misc/config.guess)" "" + cp -f /usr/share/misc/config.guess config.guess +endif + + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/mcabber. + $(MAKE) install DESTDIR=$(CURDIR)/debian/mcabber + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs ChangeLog + dh_installdocs + dh_installexamples mcabberrc.example +# dh_install +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/debian/watch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mcabber/debian/watch Sun Jul 24 15:13:53 2005 +0100 @@ -0,0 +1,24 @@ +# Example watch control file for uscan +# Rename this file to "watch" and then you can run the "uscan" command +# to check for upstream updates and more. +# See uscan(1) for format + +# Compulsory line, this is a version 3 file +version=3 + +# Uncomment to examine a Webpage +# +#http://www.example.com/downloads.php mcabber-(.*)\.tar\.gz + +# Uncomment to examine a Webserver directory +#http://www.example.com/pub/mcabber-(.*)\.tar\.gz +http://www.lilotux.net/~mikael/mcabber/files/mcabber-(.*)\.tar\.gz +http://www.lilotux.net/~mikael/mcabber/files/mcabber-(.*)\.tar\.bz2 + +# Uncommment to examine a FTP server +#ftp://ftp.example.com/pub/mcabber-(.*)\.tar\.gz debian uupdate + +# Uncomment to use Roland's hack for sourceforge based projects - YMMV! +#http://people.debian.org/~lolando/sfdlr.php?project=mcabber mcabber-([\d.]*).tar.gz + + diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/doc/mcabber.1 --- a/mcabber/doc/mcabber.1 Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/doc/mcabber.1 Sun Jul 24 15:13:53 2005 +0100 @@ -31,6 +31,9 @@ mcabber(1) is a small Jabber console client\&. For now it needs a configuration file to start, so please copy the sample mcabberrc file and adapt your connection settings\&. +You also need to have an existing Jabber account to use this software, as it cannot (un)register accounts yet\&. + + The mcabber(1) screen is divided into 4 regions\&. The \fIroster\fR, alias \fIbuddylist\fR, is on the left\&. The \fIchat window\fR, or chat buffer, is on the right\&. The \fIinput line\fR lies at the bottom of the screen, under a small \fIlog window\fR\&. @@ -180,6 +183,7 @@ \fBshow_offline\fR show offline buddies \fBtoggle_offline\fR toggle display of offline buddies \fBsearch\fR bud search for a buddy with a name or buddy containing "bud" (only in the displayed buddylist) + \fBalternate\fR jump to alternate buddy\&. The "alternate" buddy is the last buddy left while being in chat mode (this command is thus especially useful after commands like "/roster unread_first") \fBunread_first\fR jump to the first unread message \fBunread_next\fR jump to the next unread message @@ -188,8 +192,8 @@ Send the text message to the currently selected buddy\&. Can be useful if you want to send a message beginning with a slash, for example\&. .TP -\fB/status\fR [online|avail|invisible|free|dnd|notavail|away] -Set the current status\&. If no status is specified, display the current status\&. +\fB/status\fR [online|avail|invisible|free|dnd|notavail|away [StatusMessage]] +Set the current status\&. If no status is specified, display the current status\&. If a status message is specified, it will overrride the message* variables\&. .SH "CONFIGURATION FILE" @@ -212,7 +216,7 @@ .SH "BUGS" -Certainly a lot\&. Please tell me if you find one! :\-) +Certainly\&. Please tell me if you find one! :\-) .SH "AUTHOR" diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/doc/mcabber.1.html --- a/mcabber/doc/mcabber.1.html Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/doc/mcabber.1.html Sun Jul 24 15:13:53 2005 +0100 @@ -23,6 +23,8 @@

mcabber(1) is a small Jabber console client.
For now it needs a configuration file to start, so please copy the sample mcabberrc file and adapt your connection settings.

+

You also need to have an existing Jabber account to use this software, as +it cannot (un)register accounts yet.

The mcabber(1) screen is divided into 4 regions. The roster, alias buddylist, is on the left. The chat window, or chat buffer, is on the right. The input line lies at the bottom of the screen, @@ -390,7 +392,10 @@ the buddies to another group with the /move command).

-/roster bottom|top|hide_offline|show_offline|toggle_offline|unread_first|unread_next +/roster bottom|top|hide_offline|show_offline|toggle_offline +
+
+/roster alternate|unread_first|unread_next
/roster search bud @@ -448,6 +453,14 @@ +alternate + + +jump to alternate buddy. The "alternate" buddy is the last buddy left while being in chat mode (this command is thus especially useful after commands like "/roster unread_first") + + + + unread_first @@ -472,11 +485,13 @@ if you want to send a message beginning with a slash, for example.
-/status [online|avail|invisible|free|dnd|notavail|away] +/status [online|avail|invisible|free|dnd|notavail|away [StatusMessage]]
Set the current status. If no status is specified, display the - current status. + current status.
+ If a status message is specified, it will overrride the message* + variables.

CONFIGURATION FILE

@@ -487,7 +502,7 @@ $HOME/.mcabberrc Configuration file used if no other has been found $HOME/.mcabber/histo/ Default directory for storing chat history files, if enabled

BUGS

-

Certainly a lot. Please tell me if you find one! :-)

+

Certainly. Please tell me if you find one! :-)

AUTHOR

Written by Mikael BERTHE.
Originally based on Cabber, please @@ -501,8 +516,8 @@ License (GPL).

diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/doc/mcabber.1.txt --- a/mcabber/doc/mcabber.1.txt Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/doc/mcabber.1.txt Sun Jul 24 15:13:53 2005 +0100 @@ -1,7 +1,7 @@ MCABBER(1) =========== Mikael BERTHE -v0.6.4-dev, July 2005 +v0.6.5-dev, July 2005 NAME ---- @@ -17,6 +17,9 @@ For now it needs a configuration file to start, so please copy the sample mcabberrc file and adapt your connection settings. +You also need to have an existing Jabber account to use this software, as +it cannot (un)register accounts yet. + The `mcabber(1)` screen is divided into 4 regions. The 'roster', alias 'buddylist', is on the left. The 'chat window', or chat buffer, is on the right. The 'input line' lies at the bottom of the screen, @@ -162,7 +165,8 @@ This command does not work for groups, at the moment (but you can move the buddies to another group with the /move command). -/roster bottom|top|hide_offline|show_offline|toggle_offline|unread_first|unread_next:: +/roster bottom|top|hide_offline|show_offline|toggle_offline:: +/roster alternate|unread_first|unread_next:: /roster search bud:: The 'roster' command manipulates the roster/buddylist. Here are the available parameters: @@ -172,6 +176,7 @@ 'show_offline';; show offline buddies 'toggle_offline';; toggle display of offline buddies 'search' bud;; search for a buddy with a name or buddy containing "bud" (only in the displayed buddylist) + 'alternate';; jump to alternate buddy. The "alternate" buddy is the last buddy left while being in chat mode (this command is thus especially useful after commands like "/roster unread_first") 'unread_first';; jump to the first unread message 'unread_next';; jump to the next unread message @@ -179,9 +184,11 @@ Send the text message to the currently selected buddy. Can be useful if you want to send a message beginning with a slash, for example. -/status [online|avail|invisible|free|dnd|notavail|away]:: +/status [online|avail|invisible|free|dnd|notavail|away [StatusMessage]]:: Set the current status. If no status is specified, display the - current status. + current status. + + If a status message is specified, it will overrride the message* + variables. CONFIGURATION FILE ------------------ @@ -197,7 +204,7 @@ BUGS ---- -Certainly a lot. Please tell me if you find one! :-) +Certainly. Please tell me if you find one! :-) AUTHOR ------ diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/libjabber/xmltok_impl_c.h --- a/mcabber/libjabber/xmltok_impl_c.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/libjabber/xmltok_impl_c.h Sun Jul 24 15:13:53 2005 +0100 @@ -1391,7 +1391,7 @@ { enum { other, inName, inValue } state = inName; int nAtts = 0; - int open; + int open = 0; for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { switch (BYTE_TYPE(enc, ptr)) { diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/mcabberrc.example --- a/mcabber/mcabberrc.example Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/mcabberrc.example Sun Jul 24 15:13:53 2005 +0100 @@ -5,61 +5,85 @@ # If port is not given, default Jabber port will be used. # Use ssl = 1 to enable SSL -username = yourusername -#password = yourpassword -server = your.jabber.server -#port = 5222 -ssl = 0 +set username = yourusername +# Note: if the password contains leading or trailing spaces, you must +# enclose it with quotes: set password = " example password " +#set password = yourpassword +set server = your.jabber.server +#set port = 5222 +set ssl = 0 # If you don't know what a resource is, you can leave "mcabber" here. -resource = mcabber -#priority = 3 +set resource = mcabber +#set priority = 3 # Keepalive # If you need a ping/keepalive to leave your connection open, you # can use the pinginterval. Setting this option to 0 disables the ping. # Default value is 40 seconds. -#pinginterval = 40 +#set pinginterval = 40 # Set hide_offline_buddies to 1 to display only connected buddies # in the roster. -#hide_offline_buddies = 0 +#set hide_offline_buddies = 0 + +# Set the auto-away timeout, in seconds. If set to a value >0, +# mcabber will change your status to away if no real activity is detected +# (command, message, move in the buddylist...). Note: auto-away only changes +# the status when it is "available" (online) or "free_for_chat". +#set autoaway = 0 # History logging # You can save the messages history: set logging = 1 # You can load (read) the messages history: set load_logs = 1 # Default logging directory (logging_dir) is $HOME/.mcabber/histo/ -logging = 1 -#load_logs = 1 -#logging_dir = /home/mikael/.mcabber/histo/ +# Defaults for logging, load_logs are 0 (disabled) +# Note: and the logging directory must exist if you enable logging. +#set logging = 1 +#set load_logs = 1 +#set logging_dir = /home/mikael/.mcabber/histo/ # External command for events # You can specify a script or process to be launched when an event occurs. -# For now it is called the following way: -# $events_command MSG IN jabber@id -# ... when receiving a message. -#events_command = /home/mikael/.mcabber/eventcmd +# The command is called the following way: +# $events_command MSG IN jabber@id (when receiving a message) +# $events_command MSG OUT jabber@id (when sending a message) +# $events_command STATUS X jabber@id (new buddy status is X) +# See sample script in contrib/ directory. +#set events_command = /home/mikael/.mcabber/eventcmd # Debug logging # If you want advanced debug, please specify a file here. # You can enable debug in main.c before compiling mcabber, too. -#debug = /home/mikael/mcabber.log +#set debug = /home/mikael/mcabber.log # Status messages # The "message" value will override all others, take care! -#message = Unique message status -#message_avail = I'm available -#message_free = I'm free for chat -#message_dnd = Please do not disturb -#message_notavail = I'm not available -#message_away = I'm away -#message_autoaway = Auto-away (Not yet implemented) +#set message = Unique message status +#set message_avail = I'm available +#set message_free = I'm free for chat +#set message_dnd = Please do not disturb +#set message_notavail = I'm not available +#set message_away = I'm away +#set message_autoaway = Auto-away # The colors # Colors are: black, red, green, yellow, blue, magenta, cyan, white -#color_background = blue -#color_general = white -#color_newmessage = red -#color_rosternormal = magenta -#color_rosterselect = black -#color_backselected = cyan +#set color_background = blue +#set color_general = white +#set color_newmessage = red +#set color_rosternormal = magenta +#set color_rosterselect = black +#set color_backselected = cyan +# Aliases +alias online = status online +alias away = status away +alias dnd = status dnd +alias notavail = status notavail + +# Key bindings +# Ctlr-X (24) bound to /roster alternate +bind 24 = roster alternate +# F5 (269) bound to /roster toggle_offline (centericq-like, IIRC) +bind 269 = roster toggle_offline + diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/Makefile.am --- a/mcabber/src/Makefile.am Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/Makefile.am Sun Jul 24 15:13:53 2005 +0100 @@ -2,7 +2,7 @@ mcabber_SOURCES = main.c jabglue.c jabglue.h roster.c roster.h \ commands.c commands.h compl.c compl.h \ hbuf.c hbuf.h screen.c screen.h \ - settings.c settings.h parsecfg.c parsecfg.h \ + settings.c settings.h \ hooks.c hooks.h histolog.c histolog.h \ utf8.c utf8.h utils.c utils.h list.h harddefines.h diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/Makefile.mcabber --- a/mcabber/src/Makefile.mcabber Fri Jul 15 10:56:15 2005 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -# -# mcabber Makefile -# - - -# -# Available options: -# -# Environment variables: -# CPU optimize for the given processor. -# default = pentium -# DEBUG=1 disable optimizations and build for debug -# default = no -# GNU99=1 use GNU99 extensions -# default = no -# -# Targets: -# all: build executable -# clean: remove object files -# realclean: remove all generated files -# install: build & install -# dep: create dependencies -# - - -.PHONY: all clean realclean install -# dep - -CPU ?= i386 -JCLIENT = mcabber -ifndef CC -CC = gcc -endif -CFLAGS = -Wall -W -pedantic -LD = $(CC) -LDLIBS = -lncurses -lpanel -lssl -L../libjabber -L../connwrap -llibjabber -lconnwrap - -ifeq ($(DEBUG),1) -CFLAGS += -O0 -g -DDEBUG=1 -else -CFLAGS += -O2 -mcpu=$(CPU) -LDFLAGS = -s -endif - -ifeq ($(GNU99),1) -CFLAGS += -std=gnu99 -D_GNU_SOURCE -endif - -CP = cp -f - -SOURCES = \ - main.c \ - commands.c \ - screen.c \ - utils.c \ - buddies.c \ - parsecfg.c \ - jabglue.c \ - lang.c \ - utf8.c - -OBJECTS = $(SOURCES:.c=.o) - -.c.o: - $(CC) -o $@ $(CFLAGS) -c $< - -all: $(JCLIENT) - -$(JCLIENT): $(OBJECTS) - $(LD) -o $@ $(LDFLAGS) $^ $(LDLIBS) - -clean: - -$(RM) *~ - -$(RM) $(JCLIENT) - -$(RM) $(OBJECTS) -# -$(RM) depend - -realclean: clean - -$(RM) $(JCLIENT) - -install: all - $(CP) $(JCLIENT) /usr/local/bin/$(JCLIENT) - -#dep: $(SOURCES) -# makedepend -f- -Ylydialog -- $(CFLAGS) -- $(SOURCES) > depend - -#-include depend diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/commands.c --- a/mcabber/src/commands.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/commands.c Sun Jul 24 15:13:53 2005 +0100 @@ -33,23 +33,23 @@ #include "settings.h" // Commands callbacks -void do_roster(char *arg); -void do_status(char *arg); -void do_add(char *arg); -void do_del(char *arg); -void do_group(char *arg); -void do_say(char *arg); -void do_msay(char *arg); -void do_buffer(char *arg); -void do_clear(char *arg); -void do_info(char *arg); -void do_rename(char *arg); -void do_move(char *arg); -void do_set(char *arg); -void do_alias(char *arg); -void do_bind(char *arg); -void do_connect(char *arg); -void do_disconnect(char *arg); +static void do_roster(char *arg); +static void do_status(char *arg); +static void do_add(char *arg); +static void do_del(char *arg); +static void do_group(char *arg); +static void do_say(char *arg); +static void do_msay(char *arg); +static void do_buffer(char *arg); +static void do_clear(char *arg); +static void do_info(char *arg); +static void do_rename(char *arg); +static void do_move(char *arg); +static void do_set(char *arg); +static void do_alias(char *arg); +static void do_bind(char *arg); +static void do_connect(char *arg); +static void do_disconnect(char *arg); // Global variable for the commands list static GSList *Commands; @@ -118,6 +118,7 @@ compl_add_category_word(COMPL_ROSTER, "hide_offline"); compl_add_category_word(COMPL_ROSTER, "show_offline"); compl_add_category_word(COMPL_ROSTER, "toggle_offline"); + compl_add_category_word(COMPL_ROSTER, "alternate"); compl_add_category_word(COMPL_ROSTER, "search"); compl_add_category_word(COMPL_ROSTER, "unread_first"); compl_add_category_word(COMPL_ROSTER, "unread_next"); @@ -322,7 +323,7 @@ /* Commands callback functions */ -void do_roster(char *arg) +static void do_roster(char *arg) { if (!strcasecmp(arg, "top")) { scr_RosterTop(); @@ -347,6 +348,8 @@ scr_RosterUnreadMessage(0); } else if (!strcasecmp(arg, "unread_next")) { scr_RosterUnreadMessage(1); + } else if (!strcasecmp(arg, "alternate")) { + scr_RosterJumpAlternate(); } else if (!strncasecmp(arg, "search", 6)) { char *string = arg+6; if (*string && (*string != ' ')) { @@ -365,33 +368,46 @@ scr_LogPrint("Unrecognized parameter!"); } -void do_status(char *arg) +static void do_status(char *arg) { enum imstatus st; + int len; + char *msg; if (!arg || (*arg == 0)) { scr_LogPrint("Your status is: %c", imstatus2char[jb_getstatus()]); return; } - if (!strcasecmp(arg, "offline")) st = offline; - else if (!strcasecmp(arg, "online")) st = available; - else if (!strcasecmp(arg, "avail")) st = available; - else if (!strcasecmp(arg, "away")) st = away; - else if (!strcasecmp(arg, "invisible")) st = invisible; - else if (!strcasecmp(arg, "dnd")) st = dontdisturb; - else if (!strcasecmp(arg, "notavail")) st = notavail; - else if (!strcasecmp(arg, "free")) st = freeforchat; + msg = strchr(arg, ' '); + if (!msg) + len = strlen(arg); + else + len = msg - arg; + + if (!strncasecmp(arg, "offline", len)) st = offline; + else if (!strncasecmp(arg, "online", len)) st = available; + else if (!strncasecmp(arg, "avail", len)) st = available; + else if (!strncasecmp(arg, "away", len)) st = away; + else if (!strncasecmp(arg, "invisible", len)) st = invisible; + else if (!strncasecmp(arg, "dnd", len)) st = dontdisturb; + else if (!strncasecmp(arg, "notavail", len)) st = notavail; + else if (!strncasecmp(arg, "free", len)) st = freeforchat; else { scr_LogPrint("Unrecognized parameter!"); return; } - // XXX special case if offline?? - jb_setstatus(st, NULL); // TODO handle message (instead of NULL) + if (msg && st != offline && st != invisible) { + for (msg++ ; *msg && *msg == ' ' ; msg++) ; + if (!*msg) msg = NULL; + } else + msg = NULL; + + jb_setstatus(st, msg); } -void do_add(char *arg) +static void do_add(char *arg) { char *id, *nick; if (!arg || (*arg == 0)) { @@ -414,7 +430,7 @@ g_free(id); } -void do_del(char *arg) +static void do_del(char *arg) { const char *jid; @@ -431,7 +447,7 @@ jb_delbuddy(jid); } -void do_group(char *arg) +static void do_group(char *arg) { gpointer group; guint leave_windowbuddy; @@ -471,7 +487,7 @@ if (leave_windowbuddy) scr_ShowBuddyWindow(); } -void do_say(char *arg) +static void do_say(char *arg) { gpointer bud; @@ -492,7 +508,7 @@ send_message(arg); } -void do_msay(char *arg) +static void do_msay(char *arg) { /* Parameters: begin verbatim abort send */ gpointer bud; @@ -546,24 +562,24 @@ scr_set_multimode(FALSE); } -void do_buffer(char *arg) +static void do_buffer(char *arg) { if (!strcasecmp(arg, "top")) { - scr_BufferTop(); + scr_BufferTopBottom(-1); } else if (!strcasecmp(arg, "bottom")) { - scr_BufferBottom(); + scr_BufferTopBottom(1); } else if (!strcasecmp(arg, "clear")) { scr_Clear(); } else scr_LogPrint("Unrecognized parameter!"); } -void do_clear(char *arg) // Alias for "/buffer clear" +static void do_clear(char *arg) // Alias for "/buffer clear" { do_buffer("clear"); } -void do_info(char *arg) +static void do_info(char *arg) { gpointer bud; const char *jid, *name, *st_msg; @@ -610,7 +626,7 @@ g_free(buffer); } -void do_rename(char *arg) +static void do_rename(char *arg) { gpointer bud; const char *jid, *group; @@ -646,7 +662,7 @@ update_roster = TRUE; } -void do_move(char *arg) +static void do_move(char *arg) { gpointer bud; const char *jid, *name; @@ -680,7 +696,7 @@ update_roster = TRUE; } -void do_set(char *arg) +static void do_set(char *arg) { guint assign; const gchar *option, *value; @@ -710,7 +726,7 @@ } } -void do_alias(char *arg) +static void do_alias(char *arg) { guint assign; const gchar *alias, *value; @@ -749,7 +765,7 @@ } } -void do_bind(char *arg) +static void do_bind(char *arg) { guint assign; const gchar *keycode, *value; @@ -775,12 +791,12 @@ settings_set(SETTINGS_TYPE_BINDING, keycode, value); } -void do_connect(char *arg) +static void do_connect(char *arg) { mcabber_connect(); } -void do_disconnect(char *arg) +static void do_disconnect(char *arg) { jb_disconnect(); } diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/hbuf.h --- a/mcabber/src/hbuf.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/hbuf.h Sun Jul 24 15:13:53 2005 +0100 @@ -19,6 +19,7 @@ #define HBB_PREFIX_STATUS 4 #define HBB_PREFIX_AUTH 8 #define HBB_PREFIX_INFO 16 +#define HBB_PREFIX_ERR 32 typedef struct { time_t timestamp; diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/histolog.c --- a/mcabber/src/histolog.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/histolog.c Sun Jul 24 15:13:53 2005 +0100 @@ -94,7 +94,7 @@ * * Types: * - M message Info: S (send) R (receive) - * - S status Info: [oaifdcn] + * - S status Info: [_oifdna] * We don't check them, we'll trust the caller. */ @@ -229,7 +229,7 @@ int l = strlen(root_dir); if (l < 1) { scr_LogPrint("root_dir too short"); - UseFileLogging = FALSE; + UseFileLogging = FileLoadLogs = FALSE; return; } // RootDir must be slash-terminated @@ -247,11 +247,16 @@ strcpy(RootDir, home); strcat(RootDir, dir); } - // FIXME - // We should check the directory actually exists - } else // Disable history logging - if (RootDir) { - g_free(RootDir); + // Check directory permissions (should not be readable by group/others) + if (checkset_perm(RootDir, TRUE) == -1) { + // The directory does not actually exists + g_free(RootDir); + scr_LogPrint("ERROR: Can't access history log directory"); + UseFileLogging = FileLoadLogs = FALSE; + } + } else { // Disable history logging + if (RootDir) + g_free(RootDir); } } diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/hooks.c --- a/mcabber/src/hooks.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/hooks.c Sun Jul 24 15:13:53 2005 +0100 @@ -27,12 +27,15 @@ #include "roster.h" #include "histolog.h" #include "utf8.h" +#include "hbuf.h" -static char *extcommand; +static char *extcmd; -inline void hk_message_in(const char *jid, time_t timestamp, const char *msg) +inline void hk_message_in(const char *jid, time_t timestamp, const char *msg, + const char *type) { int new_guy = FALSE; + int message_flags; // If this user isn't in the roster, we add it if (!roster_exists(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)) { @@ -40,11 +43,20 @@ new_guy = TRUE; } + if (type && !strcmp(type, "error")) { + message_flags = HBB_PREFIX_ERR | HBB_PREFIX_IN; + scr_LogPrint("Error message received from <%s>", jid); + } else + message_flags = 0; + // Note: the hlog_write should not be called first, because in some // cases scr_WriteIncomingMessage() will load the history and we'd // have the message twice... - scr_WriteIncomingMessage(jid, msg, timestamp, 0); - hlog_write_message(jid, timestamp, FALSE, msg); + scr_WriteIncomingMessage(jid, msg, timestamp, message_flags); + // We don't log the message if it is an error message + if (!(message_flags & HBB_PREFIX_ERR)) + hlog_write_message(jid, timestamp, FALSE, msg); + // External command hk_ext_cmd(jid, 'M', 'R', NULL); // We need to rebuild the list if the sender is unknown or // if the sender is offline/invisible and hide_offline_buddies is set @@ -60,27 +72,33 @@ { scr_WriteOutgoingMessage(jid, msg); hlog_write_message(jid, timestamp, TRUE, msg); + // External command + hk_ext_cmd(jid, 'M', 'S', NULL); } inline void hk_statuschange(const char *jid, time_t timestamp, enum imstatus status, const char *status_msg) { - scr_LogPrint("Buddy status has changed: [%c>%c] <%s>", - imstatus2char[roster_getstatus(jid)], imstatus2char[status], jid); + scr_LogPrint("Buddy status has changed: [%c>%c] <%s> %s", + imstatus2char[roster_getstatus(jid)], imstatus2char[status], jid, + ((status_msg) ? status_msg : "")); roster_setstatus(jid, status, status_msg); buddylist_build(); scr_DrawRoster(); hlog_write_status(jid, 0, status, status_msg); + // External command + hk_ext_cmd(jid, 'S', imstatus2char[status], NULL); } inline void hk_mystatuschange(time_t timestamp, - enum imstatus old_status, enum imstatus new_status) + enum imstatus old_status, enum imstatus new_status, const char *msg) { - if (old_status == new_status) + if (!msg && (old_status == new_status)) return; - scr_LogPrint("Your status has changed: [%c>%c]", - imstatus2char[old_status], imstatus2char[new_status]); + scr_LogPrint("Your status has changed: [%c>%c] %s", + imstatus2char[old_status], imstatus2char[new_status], + ((msg) ? msg : "")); //hlog_write_status(NULL, 0, status); } @@ -92,12 +110,12 @@ // Can be called with parameter NULL to reset and free memory. void hk_ext_cmd_init(const char *command) { - if (extcommand) { - g_free(extcommand); - extcommand = NULL; + if (extcmd) { + g_free(extcmd); + extcmd = NULL; } if (command) - extcommand = g_strdup(command); + extcmd = g_strdup(command); } // hk_ext_cmd() @@ -106,21 +124,44 @@ void hk_ext_cmd(const char *jid, guchar type, guchar info, const char *data) { pid_t pid; + char *arg_type = NULL; + char *arg_info = NULL; + char *arg_data = NULL; + char status_str[2]; - if (!extcommand) return; + if (!extcmd) return; - // For now we'll only handle incoming messages - if (type != 'M') return; - if (info != 'R') return; + // Prepare arg_* (external command parameters) + switch (type) { + case 'M': + arg_type = "MSG"; + if (info == 'R') + arg_info = "IN"; + else if (info == 'S') + arg_info = "OUT"; + + break; + case 'S': + arg_type = "STATUS"; + if (strchr(imstatus2char, tolower(info))) { + status_str[0] = toupper(info); + status_str[1] = 0; + arg_info = status_str; + } + break; + default: + return; + } + + if (!arg_type || !arg_info) return; if ((pid=fork()) == -1) { scr_LogPrint("Fork error, cannot launch external command."); return; } - // I don't remember what I should do with the parent process... if (pid == 0) { // child - if (execl(extcommand, extcommand, "MSG", "IN", jid, NULL) == -1) { + if (execl(extcmd, extcmd, arg_type, arg_info, jid, arg_data) == -1) { // ut_WriteLog("Cannot execute external command.\n"); exit(1); } diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/hooks.h --- a/mcabber/src/hooks.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/hooks.h Sun Jul 24 15:13:53 2005 +0100 @@ -5,12 +5,13 @@ #include "jabglue.h" -inline void hk_message_in(const char *jid, time_t timestamp, const char *msg); +inline void hk_message_in(const char *jid, time_t timestamp, const char *msg, + const char *type); inline void hk_message_out(const char *jid, time_t timestamp, const char *msg); inline void hk_statuschange(const char *jid, time_t timestamp, enum imstatus status, char const *status_msg); inline void hk_mystatuschange(time_t timestamp, - enum imstatus old_status, enum imstatus new_status); + enum imstatus old_status, enum imstatus new_status, const char *msg); void hk_ext_cmd_init(const char *command); void hk_ext_cmd(const char *jid, guchar type, guchar info, const char *data); diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/jabglue.c --- a/mcabber/src/jabglue.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/jabglue.c Sun Jul 24 15:13:53 2005 +0100 @@ -45,8 +45,8 @@ static enum imstatus mystatus = offline; unsigned char online; -char imstatus2char[imstatus_size] = { - '_', 'o', 'i', 'f', 'd', 'n', 'a' +char imstatus2char[imstatus_size+1] = { + '_', 'o', 'i', 'f', 'd', 'n', 'a', '\0' }; static enum { @@ -139,8 +139,7 @@ port = JABBERPORT; } - //if (jc) - // free(jc); XXX + jb_disconnect(); s_id = 1; jc = jab_new((char*)jid, (char*)pass, port, ssl); @@ -250,6 +249,7 @@ void jb_setstatus(enum imstatus st, const char *msg) { xmlnode x; + char *utf8_msg; if (!online) return; @@ -298,11 +298,13 @@ if (!msg) msg = settings_get_status_msg(st); - xmlnode_insert_cdata(xmlnode_insert_tag(x, "status"), msg, + utf8_msg = utf8_encode(msg); + xmlnode_insert_cdata(xmlnode_insert_tag(x, "status"), utf8_msg, (unsigned) -1); jab_send(jc, x); xmlnode_free(x); + free(utf8_msg); //sendvisibility(); ??? @@ -311,7 +313,7 @@ if (mystatus == offline || st == offline) update_roster = TRUE; - hk_mystatuschange(0, mystatus, st); + hk_mystatuschange(0, mystatus, st, msg); mystatus = st; } @@ -563,7 +565,7 @@ */ jid = jidtodisp(from); - hk_message_in(jid, timestamp, buffer); + hk_message_in(jid, timestamp, buffer, type); g_free(jid); free(buffer); } @@ -577,7 +579,7 @@ switch(state) { case JCONN_STATE_OFF: if (previous_state != JCONN_STATE_OFF) - scr_LogPrint("+ JCONN_STATE_OFF"); + scr_LogPrint("[Jabber] Not connected to the server"); online = FALSE; mystatus = offline; @@ -586,20 +588,21 @@ break; case JCONN_STATE_CONNECTED: - scr_LogPrint("+ JCONN_STATE_CONNECTED"); + scr_LogPrint("[Jabber] Connected to the server"); break; case JCONN_STATE_AUTH: - scr_LogPrint("+ JCONN_STATE_AUTH"); + scr_LogPrint("[Jabber] Authenticating to the server"); break; case JCONN_STATE_ON: - scr_LogPrint("+ JCONN_STATE_ON"); + scr_LogPrint("[Jabber] Communication with the server established"); online = TRUE; break; case JCONN_STATE_CONNECTING: - scr_LogPrint("+ JCONN_STATE_CONNECTING"); + if (previous_state != state) + scr_LogPrint("[Jabber] Connecting to the server"); break; default: @@ -611,6 +614,7 @@ void packethandler(jconn conn, jpacket packet) { char *p, *r; + const char *m; xmlnode x, y; char *from=NULL, *type=NULL, *body=NULL, *enc=NULL; char *ns=NULL; @@ -851,19 +855,22 @@ } } - if (type && !strcmp(type, "unavailable")) { + if (type && !strcmp(type, "unavailable")) ust = offline; - } if ((x = xmlnode_get_tag(packet->x, "status")) != NULL) - p = xmlnode_get_data(x); + p = utf8_decode(xmlnode_get_data(x)); else p = NULL; r = jidtodisp(from); - if (ust != roster_getstatus(r)) + // Call hk_statuschange() if status has changed or if the + // status message is different + m = roster_getstatusmsg(r); + if ((ust != roster_getstatus(r)) || (p && (!m || strcmp(p, m)))) hk_statuschange(r, 0, ust, p); g_free(r); + if (p) free(p); break; case JPACKET_S10N: diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/main.c --- a/mcabber/src/main.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/main.c Sun Jul 24 15:13:53 2005 +0100 @@ -34,7 +34,6 @@ #include "jabglue.h" #include "screen.h" -#include "parsecfg.h" #include "settings.h" #include "roster.h" #include "commands.h" @@ -77,8 +76,12 @@ jb_set_priority(settings_opt_get_int("priority")); /* Connect to server */ - ut_WriteLog("Connecting to server: %s:%d\n", servername, port); - scr_LogPrint("Connecting to server: %s:%d", servername, port); + ut_WriteLog("Connecting to server: %s\n", servername); + scr_LogPrint("Connecting to server: %s", servername); + if (port) { + ut_WriteLog(" using port %d\n", port); + scr_LogPrint(" using port %d", port); + } jid = compose_jid(username, servername, resource); jc = jb_connect(jid, port, ssl, password); @@ -131,7 +134,7 @@ } } -void ask_password(void) +static void ask_password(void) { char *password, *p; size_t passsize = 128; @@ -165,7 +168,7 @@ return; } -void credits(void) +static void credits(void) { printf(MCABBER_VERSION "\n"); printf(EMAIL "\n"); @@ -178,7 +181,7 @@ int optval, optval2; int key; unsigned int ping; - int ret = 0; + int ret; unsigned int refresh = 0; credits(); @@ -209,13 +212,19 @@ } } + /* Initialize commands system */ + cmd_init(); + if (configFile) ut_WriteLog("Setting config file: %s\n", configFile); /* Parsing config file... */ ut_WriteLog("Parsing config file...\n"); - cfg_file(configFile); + ret = cfg_read_file(configFile); if (configFile) g_free(configFile); + /* Leave if there was an error in the config. file */ + if (ret) + exit(EXIT_FAILURE); optstring = settings_opt_get("debug"); if (optstring) ut_InitDebug(1, optstring); @@ -256,18 +265,16 @@ else scr_LogPrint("Can't connect: no password supplied"); - /* Initialize commands system */ - cmd_init(); - ut_WriteLog("Entering into main loop...\n\n"); ut_WriteLog("Ready to send/receive messages...\n"); - while (ret != 255) { + for (ret = 0 ; ret != 255 ; ) { key = scr_Getch(); /* The refresh is really an ugly hack, but we need to call doupdate() from time to time to catch the RESIZE events, because getch keep returning ERR until a real key is pressed :-( + However, it allows us to handle an autoaway check here... */ if (key != ERR) { ret = process_key(key); @@ -275,6 +282,7 @@ } else if (refresh++ > 1) { doupdate(); refresh = 0; + scr_CheckAutoAway(FALSE); } if (key != KEY_RESIZE) diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/parsecfg.c --- a/mcabber/src/parsecfg.c Fri Jul 15 10:56:15 2005 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "settings.h" -#include "utils.h" - -// cfg_file(filename) -// Read and parse config file "filename". If filename is NULL, -// try to open the configuration file at the default locations. -// -// This function comes from Cabber, and has been slightly modified. -int cfg_file(char *filename) -{ - FILE *fp; - char *buf; - char *line; - char *value; - - if (!filename) { - // Use default config file locations - char *home = getenv("HOME"); - if (!home) { - ut_WriteLog("Can't find home dir!\n"); - exit(EXIT_FAILURE); - } - filename = g_new(char, strlen(home)+24); - sprintf(filename, "%s/.mcabber/mcabberrc", home); - if ((fp = fopen(filename, "r")) == NULL) { - // 2nd try... - sprintf(filename, "%s/.mcabberrc", home); - if ((fp = fopen(filename, "r")) == NULL) { - fprintf(stderr, "Cannot open config file!\n"); - exit(EXIT_FAILURE); - } - } - g_free(filename); - } - else if ((fp = fopen(filename, "r")) == NULL) { - perror("fopen (parsecfg.c:46)"); - exit(EXIT_FAILURE); - } - - buf = g_new(char, 256); - - while (fgets(buf, 256, fp) != NULL) { - line = buf; - - while (isspace((int) *line)) - line++; - - while ((strlen(line) > 0) - && isspace((int) line[strlen(line) - 1])) - line[strlen(line) - 1] = '\0'; - - if ((*line == '\n') || (*line == '\0') || (*line == '#')) - continue; - - if ((strchr(line, '=') != NULL)) { - value = strchr(line, '='); - *value = '\0'; - value++; - - while (isspace((int) *value)) - value++; - - while ((strlen(line) > 0) - && isspace((int) line[strlen(line) - 1])) - line[strlen(line) - 1] = '\0'; - - settings_set(SETTINGS_TYPE_OPTION, line, value); - continue; - } - fprintf(stderr, "CFG: orphaned line \"%s\"\n", line); - } - g_free(buf); - return 1; -} diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/parsecfg.h --- a/mcabber/src/parsecfg.h Fri Jul 15 10:56:15 2005 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#ifndef __PARSECFG_H__ -#define __PARSECFG_H__ 1 - -int cfg_file(char *filename); -char *cfg_read(char *key); -int cfg_read_int(char *key); - -#endif diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/roster.c --- a/mcabber/src/roster.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/roster.c Sun Jul 24 15:13:53 2005 +0100 @@ -46,19 +46,20 @@ static GSList *unread_list; GList *buddylist; GList *current_buddy; +GList *alternate_buddy; /* ### Roster functions ### */ // Comparison function used to search in the roster (compares jids and types) -gint roster_compare_jid_type(roster *a, roster *b) { +static gint roster_compare_jid_type(roster *a, roster *b) { if (! (a->type & b->type)) return -1; // arbitrary (but should be != , of course) return strcasecmp(a->jid, b->jid); } // Comparison function used to sort the roster (by name) -gint roster_compare_name(roster *a, roster *b) { +static gint roster_compare_name(roster *a, roster *b) { return strcasecmp(a->name, b->name); } @@ -359,6 +360,19 @@ return roster_usr->status; } +const char *roster_getstatusmsg(const char *jid) +{ + GSList *sl_user; + roster *roster_usr; + + sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); + if (sl_user == NULL) + return offline; // Not in the roster, anyway... + + roster_usr = (roster*)sl_user->data; + return roster_usr->status_msg; +} + guint roster_gettype(const char *jid) { GSList *sl_user; @@ -406,12 +420,16 @@ GSList *sl_roster_elt = groups; roster *roster_elt; roster *roster_current_buddy = NULL; + roster *roster_alternate_buddy = NULL; int shrunk_group; // We need to remember which buddy is selected. if (current_buddy) roster_current_buddy = BUDDATA(current_buddy); current_buddy = NULL; + if (alternate_buddy) + roster_alternate_buddy = BUDDATA(alternate_buddy); + alternate_buddy = NULL; // Destroy old buddylist if (buddylist) { @@ -474,6 +492,8 @@ // Check if we can find our saved current_buddy... if (roster_current_buddy) current_buddy = g_list_find(buddylist, roster_current_buddy); + if (roster_alternate_buddy) + alternate_buddy = g_list_find(buddylist, roster_alternate_buddy); // current_buddy initialization if (!current_buddy || (g_list_position(buddylist, current_buddy) == -1)) current_buddy = g_list_first(buddylist); @@ -511,6 +531,7 @@ GSList **sl_group; GSList *sl_clone; roster *roster_clone; + int is_alternate; // A group has no group :) if (roster_usr->type & ROSTER_TYPE_GROUP) return; @@ -537,8 +558,11 @@ ((roster*)((GSList*)roster_clone->list)->data)->flags &= ~ROSTER_FLAG_HIDE; // Little trick to have current_body pointing to the cloned buddy + is_alternate = (alternate_buddy == current_buddy); buddylist = g_list_append(buddylist, roster_clone); current_buddy = g_list_find(buddylist, roster_clone); + if (is_alternate) + alternate_buddy = current_buddy; buddylist_build(); } diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/roster.h --- a/mcabber/src/roster.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/roster.h Sun Jul 24 15:13:53 2005 +0100 @@ -23,6 +23,7 @@ extern GList *buddylist; extern GList *current_buddy; +extern GList *alternate_buddy; // Macros... @@ -41,6 +42,7 @@ void roster_msg_setflag(const char *jid, guint value); void roster_settype(const char *jid, guint type); enum imstatus roster_getstatus(const char *jid); +const char *roster_getstatusmsg(const char *jid); guint roster_gettype(const char *jid); inline guint roster_exists(const char *jidname, enum findwhat type, guint roster_type); diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/screen.c --- a/mcabber/src/screen.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/screen.c Sun Jul 24 15:13:53 2005 +0100 @@ -42,7 +42,7 @@ #define window_entry(n) list_entry(n, window_entry_t, list) -inline void check_offset(int); +static inline void check_offset(int); LIST_HEAD(window_list); @@ -69,6 +69,8 @@ static char *multiline; int update_roster; int utf8_mode = 0; +static bool Autoaway; +static bool Curses; static char inputLine[INPUTLINE_LENGTH+1]; static char *ptr_inputline; @@ -81,27 +83,15 @@ /* Functions */ -int scr_WindowWidth(WINDOW * win) +static int scr_WindowWidth(WINDOW * win) { int x, y; getmaxyx(win, y, x); return x; } -void scr_clear_box(WINDOW *win, int y, int x, int height, int width, int Color) -{ - int i, j; - - wattrset(win, COLOR_PAIR(Color)); - for (i = 0; i < height; i++) { - wmove(win, y + i, x); - for (j = 0; j < width; j++) - wprintw(win, " "); - } -} - -void scr_draw_box(WINDOW * win, int y, int x, int height, int width, - int Color, chtype box, chtype border) +static void scr_draw_box(WINDOW * win, int y, int x, int height, int width, + int Color, chtype box, chtype border) { int i, j; @@ -130,7 +120,7 @@ } } -int FindColor(const char *name) +static int FindColor(const char *name) { if (!strcmp(name, "default")) return -1; @@ -154,7 +144,7 @@ return -1; } -void ParseColors(void) +static void ParseColors(void) { const char *colors[8] = { "", "", @@ -207,8 +197,7 @@ } } - -window_entry_t *scr_CreateBuddyPanel(const char *title, int dont_show) +static window_entry_t *scr_CreateBuddyPanel(const char *title, int dont_show) { int x; int y; @@ -254,11 +243,13 @@ return tmp; } -window_entry_t *scr_SearchWindow(const char *winId) +static window_entry_t *scr_SearchWindow(const char *winId) { struct list_head *pos, *n; window_entry_t *search_entry = NULL; + if (!winId) return NULL; + list_for_each_safe(pos, n, &window_list) { search_entry = window_entry(pos); if (search_entry->name) { @@ -272,7 +263,7 @@ // scr_UpdateWindow() // (Re-)Display the given chat window. -void scr_UpdateWindow(window_entry_t *win_entry) +static void scr_UpdateWindow(window_entry_t *win_entry) { int n; int width; @@ -328,6 +319,13 @@ else if (line->flags & HBB_PREFIX_OUT) dir = '>'; wprintw(win_entry->win, "%.11s *%c* ", date, dir); + } else if (line->flags & HBB_PREFIX_ERR) { + char dir = '#'; + if (line->flags & HBB_PREFIX_IN) + dir = '<'; + else if (line->flags & HBB_PREFIX_OUT) + dir = '>'; + wprintw(win_entry->win, "%.11s #%c# ", date, dir); } else if (line->flags & HBB_PREFIX_IN) wprintw(win_entry->win, "%.11s <== ", date); else if (line->flags & HBB_PREFIX_OUT) @@ -348,7 +346,7 @@ // scr_ShowWindow() // Display the chat window with the given identifier. -void scr_ShowWindow(const char *winId) +static void scr_ShowWindow(const char *winId) { window_entry_t *win_entry = scr_SearchWindow(winId); @@ -461,6 +459,7 @@ halfdelay(5); start_color(); use_default_colors(); + Curses = TRUE; ParseColors(); @@ -478,12 +477,55 @@ void scr_TerminateCurses(void) { + if (!Curses) return; clear(); refresh(); endwin(); + Curses = FALSE; return; } +void inline set_autoaway(bool setaway) +{ + static enum imstatus oldstatus; + Autoaway = setaway; + + if (setaway) { + const char *msg; + oldstatus = jb_getstatus(); + msg = settings_opt_get("message_autoaway"); + if (!msg) msg = MSG_AUTOAWAY; + jb_setstatus(away, msg); + } else { + // Back + jb_setstatus(oldstatus, NULL); + } +} + +// Check if we should enter/leave automatic away status +void scr_CheckAutoAway(bool activity) +{ + static time_t LastActivity; + enum imstatus cur_st; + unsigned int autoaway_timeout = settings_opt_get_int("autoaway"); + + if (Autoaway && activity) set_autoaway(FALSE); + if (!autoaway_timeout) return; + if (!LastActivity || activity) time(&LastActivity); + + cur_st = jb_getstatus(); + // Auto-away is disabled for the following states + if ((cur_st != available) && (cur_st != freeforchat)) + return; + + if (!activity) { + time_t now; + time(&now); + if (!Autoaway && (now > LastActivity + autoaway_timeout)) + set_autoaway(TRUE); + } +} + // scr_DrawMainWindow() // Set fullinit to TRUE to also create panels. Set it to FALSE for a resize. // @@ -499,6 +541,11 @@ logWnd_border = newwin(LOG_WIN_HEIGHT, maxX, CHAT_WIN_HEIGHT, 0); logWnd = newwin(LOG_WIN_HEIGHT-2, maxX-2, CHAT_WIN_HEIGHT+1, 1); inputWnd = newwin(1, maxX, maxY-1, 0); + if (!rosterWnd || !chatWnd || !logWnd || !inputWnd) { + scr_TerminateCurses(); + fprintf(stderr, "Cannot create windows!\n"); + exit(EXIT_FAILURE); + } wbkgd(rosterWnd, COLOR_PAIR(COLOR_GENERAL)); wbkgd(chatWnd, COLOR_PAIR(COLOR_GENERAL)); wbkgd(logWnd_border, COLOR_PAIR(COLOR_GENERAL)); @@ -608,7 +655,7 @@ } // scr_DrawRoster() -// Actually, display the buddylist on the screen. +// Display the buddylist (not really the roster) on the screen void scr_DrawRoster(void) { static guint offset = 0; @@ -743,98 +790,59 @@ return ch; } -WINDOW *scr_GetRosterWindow(void) -{ - return rosterWnd; -} - -WINDOW *scr_GetStatusWindow(void) +// set_current_buddy(newbuddy) +// Set the current_buddy to newbuddy (if not NULL) +// Lock the newbuddy, and unlock the previous current_buddy +static void set_current_buddy(GList *newbuddy) { - return chatWnd; -} + enum imstatus prev_st = imstatus_size; + /* prev_st initialized to imstatus_size, which is used as "undef" value. + * We are sure prev_st will get a different status value after the + * buddy_getstatus() call. + */ + + if (!current_buddy || !newbuddy) return; + if (newbuddy == current_buddy) return; -WINDOW *scr_GetInputWindow(void) -{ - return inputWnd; + prev_st = buddy_getstatus(BUDDATA(current_buddy)); + buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); + if (chatmode) + alternate_buddy = current_buddy; + current_buddy = newbuddy; + // Lock the buddy in the buddylist if we're in chat mode + if (chatmode) + buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); + // We should rebuild the buddylist but not everytime + // Here we check if we were locking a buddy who is actually offline, + // and hide_offline_buddies is TRUE. In which case we need to rebuild. + if (prev_st == offline && buddylist_get_hide_offline_buddies()) + buddylist_build(); + update_roster = TRUE; } // scr_RosterTop() // Go to the first buddy in the buddylist void scr_RosterTop(void) { - enum imstatus prev_st = imstatus_size; // undef - - if (current_buddy) { - prev_st = buddy_getstatus(BUDDATA(current_buddy)); - if (chatmode) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); - } - current_buddy = buddylist; - if (chatmode && current_buddy) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); - - // We should rebuild the buddylist but not everytime - // Here we check if we were locking a buddy who is actually offline, - // and hide_offline_buddies is TRUE. In which case we need to rebuild. - if (current_buddy && prev_st == offline && - buddylist_get_hide_offline_buddies()) - buddylist_build(); + set_current_buddy(buddylist); if (chatmode) scr_ShowBuddyWindow(); - update_roster = TRUE; } // scr_RosterBottom() // Go to the last buddy in the buddylist void scr_RosterBottom(void) { - enum imstatus prev_st = imstatus_size; // undef - - if (current_buddy) { - prev_st = buddy_getstatus(BUDDATA(current_buddy)); - if (chatmode) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); - } - current_buddy = g_list_last(buddylist); - // Lock the buddy in the buddylist if we're in chat mode - if (chatmode && current_buddy) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); - - // We should rebuild the buddylist but not everytime - // Here we check if we were locking a buddy who is actually offline, - // and hide_offline_buddies is TRUE. In which case we need to rebuild. - if (current_buddy && prev_st == offline && - buddylist_get_hide_offline_buddies()) - buddylist_build(); - + set_current_buddy(g_list_last(buddylist)); if (chatmode) scr_ShowBuddyWindow(); - update_roster = TRUE; } // scr_RosterUp() // Go to the previous buddy in the buddylist void scr_RosterUp(void) { - enum imstatus prev_st = imstatus_size; // undef - - if (current_buddy) { - if (g_list_previous(current_buddy)) { - prev_st = buddy_getstatus(BUDDATA(current_buddy)); - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); - current_buddy = g_list_previous(current_buddy); - // Lock the buddy in the buddylist if we're in chat mode - if (chatmode) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); - // We should rebuild the buddylist but not everytime - // Here we check if we were locking a buddy who is actually offline, - // and hide_offline_buddies is TRUE. In which case we need to rebuild. - if (prev_st == offline && buddylist_get_hide_offline_buddies()) - buddylist_build(); - update_roster = TRUE; - } - } - + set_current_buddy(g_list_previous(current_buddy)); if (chatmode) scr_ShowBuddyWindow(); } @@ -843,24 +851,7 @@ // Go to the next buddy in the buddylist void scr_RosterDown(void) { - enum imstatus prev_st = imstatus_size; // undef - - if (current_buddy) { - if (g_list_next(current_buddy)) { - prev_st = buddy_getstatus(BUDDATA(current_buddy)); - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); - current_buddy = g_list_next(current_buddy); - if (chatmode) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); - // We should rebuild the buddylist but not everytime - // Here we check if we were locking a buddy who is actually offline, - // and hide_offline_buddies is TRUE. In which case we need to rebuild. - if (prev_st == offline && buddylist_get_hide_offline_buddies()) - buddylist_build(); - update_roster = TRUE; - } - } - + set_current_buddy(g_list_next(current_buddy)); if (chatmode) scr_ShowBuddyWindow(); } @@ -869,26 +860,7 @@ // Look forward for a buddy with jid/name containing str. void scr_RosterSearch(char *str) { - GList *matching_buddy; - enum imstatus prev_st = imstatus_size; // undef - - if (current_buddy) { - matching_buddy = buddy_search(str); - if (matching_buddy) { - prev_st = buddy_getstatus(BUDDATA(current_buddy)); - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); - current_buddy = matching_buddy; - if (chatmode) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); - // We should rebuild the buddylist but not everytime - // Here we check if we were locking a buddy who is actually offline, - // and hide_offline_buddies is TRUE. In which case we need to rebuild. - if (prev_st == offline && buddylist_get_hide_offline_buddies()) - buddylist_build(); - update_roster = TRUE; - } - } - + set_current_buddy(buddy_search(str)); if (chatmode) scr_ShowBuddyWindow(); } @@ -899,122 +871,83 @@ // message from unread_list. void scr_RosterUnreadMessage(int next) { - enum imstatus prev_st = imstatus_size; // undef + gpointer unread_ptr; + gpointer refbuddata; + gpointer ngroup; + GList *nbuddy; - if (current_buddy) { - gpointer unread_ptr; - gpointer refbuddata; - gpointer ngroup; - GList *nbuddy; + if (!current_buddy) return; - if (next) refbuddata = BUDDATA(current_buddy); - else refbuddata = NULL; + if (next) refbuddata = BUDDATA(current_buddy); + else refbuddata = NULL; - unread_ptr = unread_msg(refbuddata); - if (!unread_ptr) return; + unread_ptr = unread_msg(refbuddata); + if (!unread_ptr) return; - // If buddy is in a folded group, we need to expand it - ngroup = buddy_getgroup(unread_ptr); - if (buddy_getflags(ngroup) & ROSTER_FLAG_HIDE) { - buddy_setflags(ngroup, ROSTER_FLAG_HIDE, FALSE); - buddylist_build(); - } + // If buddy is in a folded group, we need to expand it + ngroup = buddy_getgroup(unread_ptr); + if (buddy_getflags(ngroup) & ROSTER_FLAG_HIDE) { + buddy_setflags(ngroup, ROSTER_FLAG_HIDE, FALSE); + buddylist_build(); + } - nbuddy = g_list_find(buddylist, unread_ptr); - if (nbuddy) { - prev_st = buddy_getstatus(BUDDATA(current_buddy)); - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); - current_buddy = nbuddy; - if (chatmode) - buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); - // We should rebuild the buddylist but not everytime - // Here we check if we were locking a buddy who is actually offline, - // and hide_offline_buddies is TRUE. In which case we need to rebuild. - if (prev_st == offline && buddylist_get_hide_offline_buddies()) - buddylist_build(); - update_roster = TRUE; - - if (chatmode) scr_ShowBuddyWindow(); - } else scr_LogPrint("Error: nbuddy == NULL"); - } + nbuddy = g_list_find(buddylist, unread_ptr); + if (nbuddy) { + set_current_buddy(nbuddy); + if (chatmode) scr_ShowBuddyWindow(); + } else scr_LogPrint("Error: nbuddy == NULL"); } -// scr_ScrollUp() -// Scroll up the current buddy window, half a screen. -void scr_ScrollUp(void) +// scr_RosterJumpAlternate() +// Try to jump to alternate (== previous) buddy +void scr_RosterJumpAlternate(void) { - const gchar *jid; + if (!alternate_buddy || g_list_position(buddylist, alternate_buddy) == -1) + return; + set_current_buddy(alternate_buddy); + if (chatmode) + scr_ShowBuddyWindow(); +} + +// scr_ScrollUpDown() +// Scroll up/down the current buddy window, half a screen. +// (up if updown == -1, down if updown == 1) +void scr_ScrollUpDown(int updown) +{ window_entry_t *win_entry; int n, nblines; GList *hbuf_top; // Get win_entry - if (!current_buddy) - return; - jid = CURRENT_JID; - if (!jid) - return; - win_entry = scr_SearchWindow(jid); - if (!win_entry) - return; - - // Scroll up half a screen (or less) - nblines = CHAT_WIN_HEIGHT/2-1; - hbuf_top = win_entry->top; - if (!hbuf_top) { - hbuf_top = g_list_last(win_entry->hbuf); - if (!win_entry->cleared) - nblines *= 3; - else - win_entry->cleared = FALSE; - } - - n = 0; - while (hbuf_top && n < nblines && g_list_previous(hbuf_top)) { - hbuf_top = g_list_previous(hbuf_top); - n++; - } - win_entry->top = hbuf_top; + if (!current_buddy) return; + win_entry = scr_SearchWindow(CURRENT_JID); + if (!win_entry) return; - // Refresh the window - scr_UpdateWindow(win_entry); - - // Finished :) - update_panels(); - doupdate(); -} - -// scr_ScrollDown() -// Scroll down the current buddy window, half a screen. -void scr_ScrollDown(void) -{ - const gchar *jid; - window_entry_t *win_entry; - int n, nblines; - GList *hbuf_top; - - // Get win_entry - if (!current_buddy) - return; - jid = CURRENT_JID; - if (!jid) - return; - win_entry = scr_SearchWindow(jid); - if (!win_entry) - return; - - // Scroll down half a screen (or less) + // Scroll half a screen (or less) nblines = CHAT_WIN_HEIGHT/2-1; hbuf_top = win_entry->top; - for (n=0 ; hbuf_top && n < nblines ; n++) - hbuf_top = g_list_next(hbuf_top); - win_entry->top = hbuf_top; - // Check if we are at the bottom - for (n=0 ; hbuf_top && n < CHAT_WIN_HEIGHT-1 ; n++) - hbuf_top = g_list_next(hbuf_top); - if (!hbuf_top) - win_entry->top = NULL; // End reached + if (updown == -1) { // UP + if (!hbuf_top) { + hbuf_top = g_list_last(win_entry->hbuf); + if (!win_entry->cleared) + nblines *= 3; + else + win_entry->cleared = FALSE; + } + for (n=0 ; hbuf_top && n < nblines && g_list_previous(hbuf_top) ; n++) + hbuf_top = g_list_previous(hbuf_top); + win_entry->top = hbuf_top; + } else { // DOWN + for (n=0 ; hbuf_top && n < nblines ; n++) + hbuf_top = g_list_next(hbuf_top); + win_entry->top = hbuf_top; + // Check if we are at the bottom + for (n=0 ; hbuf_top && n < CHAT_WIN_HEIGHT-1 ; n++) + hbuf_top = g_list_next(hbuf_top); + if (!hbuf_top) + win_entry->top = NULL; // End reached + } // Refresh the window scr_UpdateWindow(win_entry); @@ -1028,18 +961,12 @@ // Clear the current buddy window (used for the /clear command) void scr_Clear(void) { - const gchar *jid; window_entry_t *win_entry; // Get win_entry - if (!current_buddy) - return; - jid = CURRENT_JID; - if (!jid) - return; - win_entry = scr_SearchWindow(jid); - if (!win_entry) - return; + if (!current_buddy) return; + win_entry = scr_SearchWindow(CURRENT_JID); + if (!win_entry) return; win_entry->cleared = TRUE; win_entry->top = NULL; @@ -1052,49 +979,23 @@ doupdate(); } -// scr_BufferTop() -// Jump to the head of the current buddy window -void scr_BufferTop(void) +// scr_BufferTopBottom() +// Jump to the head/tail of the current buddy window +// (top if topbottom == -1, bottom topbottom == 1) +void scr_BufferTopBottom(int topbottom) { - const gchar *jid; window_entry_t *win_entry; // Get win_entry if (!current_buddy) return; - jid = CURRENT_JID; - if (!jid) return; - win_entry = scr_SearchWindow(jid); - + win_entry = scr_SearchWindow(CURRENT_JID); if (!win_entry) return; win_entry->cleared = FALSE; - win_entry->top = g_list_first(win_entry->hbuf); - - // Refresh the window - scr_UpdateWindow(win_entry); - - // Finished :) - update_panels(); - doupdate(); -} - -// scr_BufferBottom() -// Jump to the end of the current buddy window -void scr_BufferBottom(void) -{ - const gchar *jid; - window_entry_t *win_entry; - - // Get win_entry - if (!current_buddy) return; - jid = CURRENT_JID; - if (!jid) return; - win_entry = scr_SearchWindow(jid); - - if (!win_entry) return; - - win_entry->cleared = FALSE; - win_entry->top = NULL; + if (topbottom == 1) + win_entry->top = NULL; + else + win_entry->top = g_list_first(win_entry->hbuf); // Refresh the window scr_UpdateWindow(win_entry); @@ -1118,17 +1019,23 @@ timestamp = time(NULL); strftime(buffer, 64, "[%H:%M:%S] ", localtime(×tamp)); - wprintw(logWnd, "\n%s", buffer); + if (Curses) + wprintw(logWnd, "\n%s", buffer); + else + printf("%s", buffer); va_start(ap, fmt); vsnprintf(buffer, 1024, fmt, ap); va_end(ap); - wprintw(logWnd, "%s", buffer); + if (Curses) { + wprintw(logWnd, "%s", buffer); + update_panels(); + doupdate(); + } else { + printf("%s\n", buffer); + } free(buffer); - - update_panels(); - doupdate(); } // scr_set_chatmode() @@ -1226,7 +1133,7 @@ // scr_cmdhisto_prev() // Look for previous line beginning w/ the given mask in the inputLine history // Returns NULL if none found -const char *scr_cmdhisto_prev(char *mask, guint len) +static const char *scr_cmdhisto_prev(char *mask, guint len) { GList *hl; if (!cmdhisto_cur) { @@ -1251,7 +1158,7 @@ // scr_cmdhisto_next() // Look for next line beginning w/ the given mask in the inputLine history // Returns NULL if none found -const char *scr_cmdhisto_next(char *mask, guint len) +static const char *scr_cmdhisto_next(char *mask, guint len) { GList *hl; if (!cmdhisto_cur) return NULL; @@ -1328,7 +1235,7 @@ // 0 -> command // 1 -> parameter 1 (etc.) // If > 0, then *p_row is set to the beginning of the row -int which_row(char **p_row) +static int which_row(char **p_row) { int row = -1; char *p; @@ -1361,7 +1268,7 @@ // Insert the given text at the current cursor position. // The cursor is moved. We don't check if the cursor still is in the screen // after, the caller should do that. -void scr_insert_text(const char *text) +static void scr_insert_text(const char *text) { char tmpLine[INPUTLINE_LENGTH+1]; int len = strlen(text); @@ -1379,7 +1286,7 @@ // scr_handle_tab() // Function called when tab is pressed. // Initiate or continue a completion... -void scr_handle_tab(void) +static void scr_handle_tab(void) { int nrow; char *row; @@ -1443,7 +1350,7 @@ } } -void scr_cancel_current_completion(void) +static void scr_cancel_current_completion(void) { char *c; guint back = cancel_completion(); @@ -1454,7 +1361,7 @@ *c = *(c+back); } -void scr_end_current_completion(void) +static void scr_end_current_completion(void) { done_completion(); completion_started = FALSE; @@ -1463,7 +1370,7 @@ // check_offset(int direction) // Check inputline_offset value, and make sure the cursor is inside the // screen. -inline void check_offset(int direction) +static inline void check_offset(int direction) { // Left side if (inputline_offset && direction <= 0) { @@ -1482,7 +1389,7 @@ } } -inline void refresh_inputline(void) +static inline void refresh_inputline(void) { mvwprintw(inputWnd, 0,0, "%s", inputLine + inputline_offset); wclrtoeol(inputWnd); @@ -1555,6 +1462,7 @@ break; case '\n': // Enter case 15: // Ctrl-o ("accept-line-and-down-history") + scr_CheckAutoAway(TRUE); if (process_line(inputLine)) return 255; // Add line to history @@ -1596,9 +1504,11 @@ } break; case KEY_PPAGE: + scr_CheckAutoAway(TRUE); scr_RosterUp(); break; case KEY_NPAGE: + scr_CheckAutoAway(TRUE); scr_RosterDown(); break; case KEY_HOME: @@ -1621,12 +1531,13 @@ *ptr_inputline = 0; break; case 16: // Ctrl-p - scr_ScrollUp(); + scr_ScrollUpDown(-1); break; case 14: // Ctrl-n - scr_ScrollDown(); + scr_ScrollUpDown(1); break; case 17: // Ctrl-q + scr_CheckAutoAway(TRUE); scr_RosterUnreadMessage(1); // next unread message break; case 20: // Ctrl-t @@ -1636,6 +1547,7 @@ readline_backward_kill_word(); break; case 27: // ESC + scr_CheckAutoAway(TRUE); currentWindow = NULL; chatmode = FALSE; if (current_buddy) @@ -1646,6 +1558,7 @@ break; case 12: // Ctrl-l case KEY_RESIZE: + scr_CheckAutoAway(TRUE); scr_Resize(); break; default: @@ -1653,6 +1566,7 @@ const gchar *boundcmd = isbound(key); if (boundcmd) { gchar *cmd = g_strdup_printf("/%s", boundcmd); + scr_CheckAutoAway(TRUE); if (process_command(cmd)) return 255; g_free(cmd); diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/screen.h --- a/mcabber/src/screen.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/screen.h Sun Jul 24 15:13:53 2005 +0100 @@ -39,19 +39,19 @@ inline const char *scr_get_multiline(); void scr_handle_sigint(void); -WINDOW *scr_GetInputWindow(void); - int scr_Getch(void); int process_key(int); +void scr_CheckAutoAway(bool activity); + // For commands... void scr_RosterTop(void); void scr_RosterBottom(void); void scr_RosterSearch(char *); -void scr_BufferTop(void); -void scr_BufferBottom(void); +void scr_BufferTopBottom(int topbottom); void scr_Clear(void); void scr_RosterUnreadMessage(int); +void scr_RosterJumpAlternate(void); #endif diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/settings.c --- a/mcabber/src/settings.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/settings.c Sun Jul 24 15:13:53 2005 +0100 @@ -24,6 +24,9 @@ #include #include "settings.h" +#include "commands.h" +#include "utils.h" +#include "screen.h" static GSList *option; static GSList *alias; @@ -35,7 +38,7 @@ gchar *value; } T_setting; -inline GSList **get_list_ptr(guint type) +static inline GSList **get_list_ptr(guint type) { if (type == SETTINGS_TYPE_OPTION) return &option; else if (type == SETTINGS_TYPE_ALIAS) return &alias; @@ -44,7 +47,7 @@ } // Return a pointer to the node with the requested key, or NULL if none found -GSList *settings_find(GSList *list, const gchar *key) +static GSList *settings_find(GSList *list, const gchar *key) { GSList *ptr; @@ -59,6 +62,98 @@ /* -- */ +// cfg_read_file(filename) +// Read and parse config file "filename". If filename is NULL, +// try to open the configuration file at the default locations. +// +int cfg_read_file(char *filename) +{ + FILE *fp; + char *buf; + char *line, *eol; + unsigned int ln = 0; + int err = 0; + + if (!filename) { + // Use default config file locations + char *home = getenv("HOME"); + if (!home) { + ut_WriteLog("Can't find home dir!\n"); + fprintf(stderr, "Can't find home dir!\n"); + return -1; + } + filename = g_new(char, strlen(home)+24); + sprintf(filename, "%s/.mcabber/mcabberrc", home); + if ((fp = fopen(filename, "r")) == NULL) { + // 2nd try... + sprintf(filename, "%s/.mcabberrc", home); + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Cannot open config file!\n"); + return -1; + } + } + // Check configuration file permissions + // As it could contain sensitive data, we make it user-readable only + checkset_perm(filename, TRUE); + // Check mcabber dir. There we just warn, we don't change the modes + sprintf(filename, "%s/.mcabber/", home); + checkset_perm(filename, FALSE); + g_free(filename); + } else { + if ((fp = fopen(filename, "r")) == NULL) { + perror("fopen (cfg_file())"); + return -1; + } + // Check configuration file permissions (see above) + checkset_perm(filename, TRUE); + } + + buf = g_new(char, 512); + + while (fgets(buf+1, 511, fp) != NULL) { + // The first char is reserved to add a '/', to make a command line + line = buf+1; + ln++; + + // Strip leading spaces + while (isspace(*line)) + line++; + + // Make eol point to the last char of the line + for (eol = line ; *eol ; eol++) + ; + if (eol > line) + eol--; + + // Strip trailing spaces + while (eol > line && isspace(*eol)) + *eol-- = 0; + + // Ignore empty lines and comments + if ((*line == '\n') || (*line == '\0') || (*line == '#')) + continue; + + if ((strchr(line, '=') != NULL)) { + // Only accept the set, alias and bind commands + if (strncmp(line, "set ", 4) && + strncmp(line, "bind ", 5) && + strncmp(line, "alias ", 6)) { + scr_LogPrint("Error in configuration file (l. %d): bad command", ln); + err++; + continue; + } + *(--line) = '/'; // Set the leading '/' to build a command line + process_command(line); // Process the command + } else { + scr_LogPrint("Error in configuration file (l. %d): no assignment", ln); + err++; + } + } + g_free(buf); + fclose(fp); + return err; +} + // parse_assigment(assignment, pkey, pval) // Read assignment and split it to key, value // @@ -119,6 +214,12 @@ if (t < val) return TRUE; // no value (variable reset for example) + // If the value begins and ends with quotes ("), these quotes are + // removed and whitespace is not stripped + if ((t>val) && (*val == '"' && *t == '"')) { + val++; + t--; + } *pval = g_strndup(val, t+1-val); return TRUE; } diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/settings.h --- a/mcabber/src/settings.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/settings.h Sun Jul 24 15:13:53 2005 +0100 @@ -16,7 +16,7 @@ #define MSG_DND "Busy" #define MSG_NOTAVAIL "Not available" #define MSG_AWAY "Away" -#define MSG_AUTOAWAY "Auto away" +#define MSG_AUTOAWAY "Auto away status (idle)" #define SETTINGS_TYPE_OPTION 1 @@ -26,6 +26,7 @@ #define settings_opt_get(k) settings_get(SETTINGS_TYPE_OPTION, k) #define settings_opt_get_int(k) settings_get_int(SETTINGS_TYPE_OPTION, k) +int cfg_read_file(char *filename); guint parse_assigment(gchar *assignment, const gchar **pkey, const gchar **pval); void settings_set(guint type, const gchar *key, const gchar *value); diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/utf8.c --- a/mcabber/src/utf8.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/utf8.c Sun Jul 24 15:13:53 2005 +0100 @@ -13,8 +13,11 @@ */ char *utf8_decode(const char *src) { - char *ret = calloc(1, strlen(src) + 1); - unsigned char *aux = (unsigned char*)ret; + unsigned char *ret, *aux; + + if (!src) return NULL; + + aux = ret = calloc(1, strlen(src) + 1); while (*src) { unsigned char lead = *src++; @@ -27,7 +30,7 @@ aux++; } - return ret; + return (char*)ret; } @@ -40,8 +43,11 @@ */ char *utf8_encode(const char *src) { - char *ret = calloc(1, (strlen(src) * 2) + 1); - unsigned char *aux = (unsigned char*)ret; + unsigned char *ret, *aux; + + if (!src) return NULL; + + aux = ret = calloc(1, (strlen(src) * 2) + 1); while (*src) { unsigned char ch = *src++; @@ -53,5 +59,5 @@ } } - return ret; + return (char*)ret; } diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/utils.c --- a/mcabber/src/utils.c Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/utils.c Sun Jul 24 15:13:53 2005 +0100 @@ -26,8 +26,12 @@ #include #include #include +#include +#include +#include #include +#include "screen.h" static int DebugEnabled; static char *FName; @@ -90,6 +94,45 @@ } } +// checkset_perm(name, setmode) +// Check the permissions of the "name" file/dir +// If setmode is true, correct the permissions if they are wrong +// Return values: -1 == bad file/dir, 0 == success, 1 == cannot correct +int checkset_perm(const char *name, unsigned int setmode) +{ + int fd; + struct stat buf; + + fd = lstat(name, &buf); + if (fd == -1) return -1; + + if (buf.st_uid != geteuid()) { + scr_LogPrint("Wrong file owner [%s]", name); + return 1; + } + + if (buf.st_mode & (S_IRGRP | S_IWGRP | S_IXGRP) || + buf.st_mode & (S_IROTH | S_IWOTH | S_IXOTH)) { + if (setmode) { + mode_t newmode = 0; + scr_LogPrint("Bad permissions [%s]", name); + if (S_ISDIR(buf.st_mode)) + newmode |= S_IXUSR; + newmode |= S_IRUSR | S_IWUSR; + if (chmod(name, newmode)) { + scr_LogPrint("WARNING: Failed to correct permissions!"); + return 1; + } + scr_LogPrint("Permissions have been corrected"); + } else { + scr_LogPrint("WARNING: Bad permissions [%s]", name); + return 1; + } + } + + return 0; +} + // to_iso8601(dststr, timestamp) // Convert timestamp to iso8601 format, and store it in dststr. // NOTE: dststr should be at last 19 chars long. @@ -185,4 +228,3 @@ return retval; } - diff -r 65aa05520556 -r 33b8e801ffa6 mcabber/src/utils.h --- a/mcabber/src/utils.h Fri Jul 15 10:56:15 2005 +0100 +++ b/mcabber/src/utils.h Sun Jul 24 15:13:53 2005 +0100 @@ -4,6 +4,8 @@ void ut_InitDebug(unsigned int level, const char *file); void ut_WriteLog(const char *fmt, ...); +int checkset_perm(const char *name, unsigned int setmode); + int to_iso8601(char *dststr, time_t timestamp); time_t from_iso8601(const char *timestamp, int utc);