changeset 0:b3b2332715fb

Tailorization of /trunk Import of the upstream sources from Repository: file:///tmp/svn-mcabber Module: /trunk Revision: 15
author tailor@frmp8452
date Thu, 30 Jun 2005 21:39:31 +0000
parents
children da1fb510081e
files .hgignore mcabber/ACKNOWLEDGEMENT mcabber/COPYING mcabber/Changelog mcabber/Makefile mcabber/README mcabber/TODO mcabber/buddies.c mcabber/buddies.h mcabber/cabberrc.example mcabber/harddefines.h mcabber/lang.c mcabber/lang.h mcabber/lang/POSIX.txt mcabber/lang/es_ES.txt mcabber/list.h mcabber/main.c mcabber/parsecfg.c mcabber/parsecfg.h mcabber/screen.c mcabber/screen.h mcabber/server.c mcabber/server.h mcabber/socket.c mcabber/socket.h mcabber/utf8.c mcabber/utf8.h mcabber/utils.c mcabber/utils.h
diffstat 29 files changed, 3133 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,9 @@
+(^|/)\.svn($|/)
+(^|/)\_darcs($|/)
+(^|/)CVS($|/)
+(^|/)\.cdv($|/)
+(^|/)MT($|/)
+(^|/)\.hg($|/)
+(^|/)\.bzr($|/)
+^tailor.log$
+^tailor.info$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/ACKNOWLEDGEMENT	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,16 @@
+Special Thanks to:
+    Daniel Borca   (http://www.geocities.com/dborca).
+		   Many of the new code is his own work!!!
+		   Thanks Daniel!!!
+
+Thanks to:
+    Abrililla	   (???)
+    Gabber	   (http://gabber.sourceforge.net)
+    Manolo Romero  (cobreti@mundivia.es)    
+    NexusX	   (nexusx666@ajmacias.com)
+    Pablo2000	   (josepablosc@wanadoo.es)
+    Pras           (???)
+    Ted		   (ted@php.net)
+    Thomas Fischer (th.fischer@gmx.net)
+    _Yed_	   (#linux at irc-hispano)
+    ZJoyKiller 	   (#linux at irc-hispano)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/COPYING	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/Changelog	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,46 @@
+--[cabber 0.5.0-test1]--
+  - unification of lists in list.h
+  - changed UI... now is multiwindow and have popups!!!
+  - roster is now capable of add/delete buddies (very primitive and buggy!)
+  - improved many routines. Thanks to Daniel Borca.
+  - Added i18n function to translate cabber to others languages
+  - TODO: management of buddies away status...
+
+--[cabber 0.4.0-test5]--
+  - many bugs fixed: (roster, utf8...)
+  
+--[cabber 0.4.0-test4]--
+  - added UTF8 encoding/decoding (yes, it have bugs...)
+  - added default color for make cabber transparent (Johannes WeiBl)
+  - fixed cursor position.
+  
+--[cabber 0.4.0-test3]--
+  - rewritten routine "receivedata" at socket.c (bug #1: Johannes WeiBl)
+  - ignored left and rigth keys until i implement input line editor.
+  - colors are stored in $HOME/.cabberrc
+	- see cabberrc.example ;-)
+	
+--[cabber 0.4.0-test2]--
+  - not public.	
+
+--[cabber 0.4.0-test1]--
+  - many routines has been rewritten again d8-)
+  
+    * use of lists instead of stacks for store data
+	- stack.c is not needed anymore, i use list.c instead.
+	- added a ugly routine for sort list (improve it!!)
+
+    * socket module has been rewritten and improved:
+	- O_NONBLOCK eliminated
+	  
+    * module parse.c has been rewritten: now is more effective.
+
+    * the XML parser is now more effective (i hope!)	 
+
+    * contact list:
+	- it have scroll bar now,  (manoleT have a large list of contacts ;-)
+	- now contacts are sorted alphabetically.
+	
+    * a lot of new bugs... sorry, but my main pc is broken. This version
+      of cabber has been made in my laptop.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/Makefile	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,80 @@
+#
+# mcabber Makefile
+#
+
+
+#
+#  Available options:
+#
+#    Environment variables:
+#	CPU		optimize for the given processor.
+#			default = pentium
+#	DEBUG=1		disable optimizations and build for debug
+#			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
+
+CC = gcc
+CFLAGS = -Wall -W -pedantic
+LD = gcc
+LDLIBS = -lncurses -lpanel
+
+ifeq ($(DEBUG),1)
+CFLAGS += -O0 -g -DDEBUG=1
+else
+CFLAGS += -O2 -mcpu=$(CPU)
+LDFLAGS = -s
+endif
+
+CP = cp -f
+
+SOURCES = \
+    main.c \
+    screen.c \
+    utils.c \
+    buddies.c \
+    parsecfg.c \
+    server.c \
+    socket.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/bin/$(JCLIENT)
+
+#dep: $(SOURCES)
+#	makedepend -f- -Ylydialog -- $(CFLAGS) -- $(SOURCES) > depend
+
+#-include depend
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/README	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,17 @@
+Well, the documentation is missing yet, but...
+
+!!!!!! SEE mcabberrc.example !!!!!!
+
+configfile:
+    The configfile will be placed in $HOME/.mcabberrc
+    and it will be:
+	
+	    username = username
+	    password = yourpassword
+	    server = serveryou.use
+	    resource = yourresourcenameOFFICE
+	    passtype = plain  (or sha1)
+	    
+
+That's all folks! (by the moment ;-)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/TODO	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,7 @@
+A "few" things :-)
+
+    * write XML code to add/delete buddies (the code is primitive)
+    * add control over delete buddies
+    * ...
+    * ...
+    * and many many things!!! :-)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/buddies.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,366 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include <panel.h>
+#include "screen.h"
+#include "buddies.h"
+
+#include "lang.h"
+#include "utils.h"
+#include "server.h"
+#include "list.h"
+#include "harddefines.h"
+
+/* global vars for BUDDIES.C */
+int buddySelected = 1;		/* Hold the selected Buddy  */
+int buddyOffset = 0;		/* Hold the roster offset   */
+
+static LIST_HEAD(buddy_list);
+static LIST_HEAD(sorted_buddies);
+#define buddy_entry(n) list_entry(n, buddy_entry_t, list)
+
+
+void bud_SetBuddyStatus(char *jidfrom, int status)
+{
+  struct list_head *pos, *n;
+  buddy_entry_t *tmp;
+  int changed = 0;
+  char *buffer = (char *) malloc(4096);
+
+  list_for_each_safe(pos, n, &buddy_list) {
+    tmp = buddy_entry(pos);
+    if (!strcmp(tmp->jid, jidfrom)) {
+      if (tmp->flags != status) {
+	tmp->flags = status;
+	changed = 1;
+      }
+      break;
+    }
+  }
+  if (changed) {
+    bud_DrawRoster(scr_GetRosterWindow());
+    switch (status) {
+    case FLAG_BUDDY_DISCONNECTED:
+      sprintf(buffer, "--> %s %s!", jidfrom, i18n("disconected"));
+      break;
+
+    case FLAG_BUDDY_CONNECTED:
+      sprintf(buffer, "--> %s %s!", jidfrom, i18n("connected"));
+      break;
+    }
+    scr_WriteInWindow(i18n("status window"), buffer, TRUE);
+  }
+  free(buffer);
+}
+
+int compara(buddy_entry_t * t1, buddy_entry_t * t2)
+{
+  const char *s1 =
+      (const char *) (STR_EMPTY(t1->name) ? t1->jid : t1->name);
+  const char *s2 =
+      (const char *) (STR_EMPTY(t2->name) ? t2->jid : t2->name);
+  return strcasecmp(s1, s2);
+}
+
+void bud_SortRoster(void)
+{
+  buddy_entry_t *indice, *tmp;
+  struct list_head *pos, *n;
+
+  while (!list_empty(&buddy_list)) {
+    indice = NULL;
+    tmp = NULL;
+    list_for_each_safe(pos, n, &buddy_list) {
+      if (!indice) {
+	indice = buddy_entry(pos);
+	tmp = buddy_entry(pos);
+      } else {
+	tmp = buddy_entry(pos);
+	if (compara(indice, tmp) > 0) {
+	  indice = tmp;
+	}
+      }
+    }
+    list_move_tail(&indice->list, &sorted_buddies);
+  }
+  list_splice(&sorted_buddies, &buddy_list);
+}
+
+void bud_ParseBuddies(char *roster)
+{
+  buddy_entry_t *tmp = NULL;
+  char *aux;
+  char *p, *str;
+
+  ut_WriteLog("[roster]: %s\n\n", roster);
+
+  while ((aux = ut_strrstr(roster, "<item")) != NULL) {
+    char *jid = getattr(aux, "jid='");
+    char *name = getattr(aux, "name='");
+    char *group = gettag(aux, "group='");
+
+    *aux = '\0';
+
+    tmp = (buddy_entry_t *) calloc(1, sizeof(buddy_entry_t));
+
+    tmp->flags = FLAG_BUDDY_DISCONNECTED;
+
+    if (strncmp(jid, "UNK", 3)) {
+      char *res = strstr(jid, "/");
+      if (res)
+	*res = '\0';
+
+      tmp->jid = (char *) malloc(strlen(jid) + 1);
+      strcpy(tmp->jid, jid);
+      free(jid);
+    }
+
+    if (strncmp(name, "UNK", 3)) {
+      tmp->name = (char *) calloc(1, strlen(name) + 1);
+      strcpy(tmp->name, name);
+      free(name);
+    } else {
+      tmp->name = (char *) calloc(1, strlen(tmp->jid) + 1);
+      str = strdup(tmp->jid);
+      p = strstr(str, "@");
+      if (p) {
+	*p = '\0';
+      }
+      strncpy(tmp->name, str, 18);
+      free(str);
+    }
+
+    if (strncmp(group, "UNK", 3)) {
+      tmp->group = (char *) malloc(strlen(group) + 1);
+      strcpy(tmp->group, group);
+      free(group);
+    }
+
+    if (!strncmp(tmp->jid, "msn.", 4)) {
+      sprintf(tmp->name, "%c MSN %c", 254, 254);
+    }
+
+    if (!STR_EMPTY(tmp->jid)) {
+      list_add_tail(&tmp->list, &buddy_list);
+    } else {
+      if (tmp->jid)
+	free(tmp->jid);
+      if (tmp->name)
+	free(tmp->name);
+      if (tmp->group)
+	free(tmp->group);
+      free(tmp);
+    }
+  }
+  free(roster);
+
+  bud_SortRoster();
+}
+
+/* Desc: Initialize buddy list
+ * 
+ * In : none
+ * Out: none
+ *
+ * Note: none
+ */
+void bud_InitBuddies(int sock)
+{
+  char *roster;
+  roster = srv_getroster(sock);
+  bud_ParseBuddies(roster);
+}
+
+/* Desc: Destroy (and free) buddy list
+ * 
+ * In : none
+ * Out: none
+ *
+ * Note: none
+ */
+void bud_TerminateBuddies(void)
+{
+}
+
+/* Desc: Count elements in buddy list
+ * 
+ * In : none
+ * Out: number of buddies
+ *
+ * Note: none
+ */
+int bud_BuddyCount(void)
+{
+  int i = 0;
+  struct list_head *pos, *n;
+
+  list_for_each_safe(pos, n, &buddy_list) {
+    i++;
+  }
+  return i;
+}
+
+/* Desc: Draw the roster in roster window
+ * 
+ * In : roster window
+ * Out: none
+ *
+ * Note: none
+ */
+void bud_DrawRoster(WINDOW * win)
+{
+  buddy_entry_t *tmp = NULL;
+  struct list_head *pos, *nn;
+  int i = 1;
+  int n;
+  int maxx, maxy;
+  int fakeOffset = buddyOffset;
+
+  keypad(win, TRUE);
+  getmaxyx(win, maxy, maxx);
+
+
+  /* cleanup of roster window */
+  wattrset(win, COLOR_PAIR(COLOR_GENERAL));
+  for (i = 1; i < maxy - 1; i++) {
+    mvwprintw(win, i, 1, "");
+    for (n = 2; n < maxx; n++)
+      waddch(win, ' ');
+  }
+
+  i = 1;
+  list_for_each_safe(pos, nn, &buddy_list) {
+
+    if (fakeOffset > 0) {
+      fakeOffset--;
+      continue;
+    }
+
+    tmp = buddy_entry(pos);
+
+    if ((tmp->flags && FLAG_BUDDY_CONNECTED) == 1) {
+      if (i == (buddySelected - buddyOffset))
+	wattrset(win, COLOR_PAIR(COLOR_BD_CONSEL));
+      else
+	wattrset(win, COLOR_PAIR(COLOR_BD_CON));
+    } else {
+      if (i == (buddySelected - buddyOffset))
+	wattrset(win, COLOR_PAIR(COLOR_BD_DESSEL));
+      else
+	wattrset(win, COLOR_PAIR(COLOR_BD_DES));
+    }
+    mvwprintw(win, i, 1, "");
+    for (n = 2; n < maxx; n++)
+      waddch(win, ' ');
+    mvwprintw(win, i, (maxx - strlen(tmp->name)) / 2, "%s", tmp->name);
+    i++;
+    if (i >= maxy - 1)
+      break;
+  }
+  update_panels();
+  doupdate();
+}
+
+/* Desc: Change selected buddy (one position down)
+ * 
+ * In : none
+ * Out: none
+ *
+ * Note: none
+ */
+void bud_RosterDown(void)
+{
+  int x, y;
+  getmaxyx(scr_GetRosterWindow(), y, x);
+  y -= 2;
+
+  if (buddySelected < bud_BuddyCount()) {
+    buddySelected++;
+    if (buddySelected > y)
+      buddyOffset++;
+    bud_DrawRoster(scr_GetRosterWindow());
+  }
+}
+
+/* Desc: Change selected buddy (one position up)
+ * 
+ * In : none
+ * Out: none
+ *
+ * Note: none
+ */
+void bud_RosterUp(void)
+{
+  if (buddySelected > 1) {
+    buddySelected--;
+    if (buddySelected - buddyOffset < 1)
+      buddyOffset--;
+    bud_DrawRoster(scr_GetRosterWindow());
+  }
+}
+
+/* Desc: Retrieve info for selected buddy
+ * 
+ * In : none
+ * Out: (buddy_entry_t *) of selected buddy
+ *
+ * Note: none
+ */
+buddy_entry_t *bud_SelectedInfo(void)
+{
+  struct list_head *pos, *n;
+  buddy_entry_t *tmp = NULL;
+
+  int i = 0;
+
+  list_for_each_safe(pos, n, &buddy_list) {
+    tmp = buddy_entry(pos);
+    if (i == buddySelected - 1) {
+      return tmp;
+    }
+    i++;
+  }
+  return NULL;
+}
+
+void bud_AddBuddy(int sock)
+{
+  char *buffer = (char *) calloc(1, 1024);
+  char *buffer2 = (char *) calloc(1, 1024);
+  char *p, *str;
+  buddy_entry_t *tmp;
+
+  ut_CenterMessage(i18n("write jid here"), 60, buffer2);
+  scr_CreatePopup(i18n("Add jid"), buffer2, 60, 1, buffer);
+
+  if (!STR_EMPTY(buffer)) {
+    tmp = (buddy_entry_t *) calloc(1, sizeof(buddy_entry_t));
+    tmp->jid = (char *) malloc(strlen(buffer) + 1);
+    strcpy(tmp->jid, buffer);
+    tmp->name = (char *) malloc(strlen(buffer) + 1);
+
+    str = strdup(buffer);
+    p = strstr(str, "@");
+    if (p) {
+      *p = '\0';
+    }
+    strcpy(tmp->name, str);
+    free(str);
+
+    list_add_tail(&tmp->list, &buddy_list);
+    buddySelected = 1;
+    bud_DrawRoster(scr_GetRosterWindow());
+    srv_AddBuddy(sock, tmp->jid);
+  }
+  free(buffer);
+}
+
+void bud_DeleteBuddy(int sock)
+{
+  buddy_entry_t *tmp = bud_SelectedInfo();
+  srv_DelBuddy(sock, tmp->jid);
+  list_del(&tmp->list);
+  buddySelected = 1;
+  bud_DrawRoster(scr_GetRosterWindow());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/buddies.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,29 @@
+#ifndef __BUDDIES_H__
+#define __BUDDIES_H__ 1
+
+#include <ncurses.h>
+#include "list.h"
+
+/* Definición de tipos */
+typedef struct _buddy_entry_t {
+  char *jid;
+  char *name;
+  char *group;
+  char *resource;
+  int flags;
+  struct list_head list;
+} buddy_entry_t;
+
+void bud_DrawRoster(WINDOW * win);
+void bud_RosterDown(void);
+void bud_RosterUp(void);
+void bud_InitBuddies(int sock);
+void bud_TerminateBuddies(void);
+int bud_BuddyCount(void);
+void bud_SetBuddyStatus(char *jidfrom, int status);
+void bud_ParseBuddies(char *roster);
+void bud_AddBuddy(int sock);
+void bud_DeleteBuddy(int sock);
+buddy_entry_t *bud_SelectedInfo(void);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/cabberrc.example	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,18 @@
+username = yourusername
+password = yourpassword
+server = your.jabber.server
+port = 5222
+resource = yourresource
+passtype = plain
+
+
+#now, the colors
+#color are: black, red, green, yellow, blue, magenta, cyan, white
+color_background = blue
+color_backselected = cyan
+color_borderlines = white
+color_jidonlineselected = black
+color_jidonline = green
+color_jidofflineselected = red
+color_jidoffline = red
+color_text = white
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/harddefines.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,15 @@
+#ifndef __AJMACIAS__
+#define __AJMACIAS__ 0xWIN!
+
+#define VERSION "MCabber v0.6.0-dev -- based on http://cabber.sourceforge.net"
+#define EMAIL "Email: bmikael [at] lists [dot] lilotux [dot] net"
+
+#define STR_EMPTY(s) ((s)[0] == '\0')
+
+#define FLAG_BUDDY_DISCONNECTED         0x00
+#define FLAG_BUDDY_CONNECTED            0x01
+#define FLAG_BUDDY_AWAY                 0x02
+#define FLAG_BUDDY_XAWAY                0x04
+#define FLAG_BUDDY_HASMESSAGE           0x08
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/lang.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+
+#include "utils.h"
+
+char Lang[100];
+
+void lng_InitLanguage(void)
+{
+  FILE *fp;
+  memset(Lang, 0, 100);
+  sprintf(Lang, "./lang/%s.txt", getenv("LANG"));
+/*    strcpy(Lang, "./lang/");
+    strcat(Lang, getenv("LANG"));
+    strcat(Lang, ".txt");
+*/
+  if ((fp = fopen(Lang, "r")) == NULL) {
+    /* reverting to default */
+    ut_WriteLog("Reverting language to default: POSIX\n");
+    strcpy(Lang, "./lang/POSIX.txt");
+  } else {
+    fclose(fp);
+    ut_WriteLog("Setting language to %s\n", getenv("LANG"));
+  }
+}
+
+char *i18n(char *text)
+{
+  /* hack */
+  char *buf = (char *) malloc(1024);
+  static char result[1024];
+  FILE *fp;
+  char *line;
+  char *value;
+  int found = 0;
+
+  memset(result, 0, 1024);
+
+  if ((fp = fopen(Lang, "r")) != NULL) {
+    while ((fgets(buf, 1024, fp) != NULL) && (!found)) {
+      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';
+
+	if (!strcasecmp(line, text)) {
+	  strcpy(result, value);
+	  found = 1;
+	}
+	continue;
+      }
+      /* fprintf(stderr, "CFG: orphaned line \"%s\"\n", line); */
+    }
+    fclose(fp);
+  }
+
+  if (!found) {
+    strcpy(result, text);
+  }
+
+  free(buf);
+  return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/lang.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,7 @@
+#ifndef __LANG_H__
+#define __LANG_H__ 1
+
+void lng_InitLanguage(void);
+char *i18n(char *text);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/lang/POSIX.txt	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,21 @@
+#########################
+# text for help message #
+#########################
+#note the same lenght of lines, sorry!
+
+add contact		= Add contact............
+delete contact		= Delete contact.........
+view buddy window	= Show buddy Window......
+send message		= Send Message...........
+#########################
+
+exit			= Exit
+help 			= Help
+Press any key 		= Press any key...
+roster 			= Contacts
+status window 		= Status Window
+write your message here = Write your message here
+write jid here		= Write jid here
+
+conected		= connected
+disconnected		= disconnected
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/lang/es_ES.txt	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,21 @@
+#########################
+# text for help message #
+#########################
+#note the same lenght of lines, sorry!
+
+add contact		= Añadir contacto........
+delete contact		= Borrar contacto........
+view buddy window	= Ver ventana contacto...
+send message		= Enviar mensaje.........
+#########################
+
+exit			= Salir
+help 			= Ayuda
+Press any key 		= Pulsa una tecla
+roster 			= Contactos
+status window 		= Ventana de estado
+write your message here = Escriba aquí su mensaje!
+write jid here		= Escriba aquí el jid que desea añadir?
+
+connected		= conectado
+disconnected		= desconectado
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/list.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,213 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+  struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void
+__list_add(struct list_head *new,
+	   struct list_head *prev, struct list_head *next)
+{
+  next->prev = new;
+  new->next = next;
+  new->prev = prev;
+  prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+  __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void
+list_add_tail(struct list_head *new, struct list_head *head)
+{
+  __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
+{
+  next->prev = prev;
+  prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+  __list_del(entry->prev, entry->next);
+  entry->next = (void *) 0;
+  entry->prev = (void *) 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+  __list_del(entry->prev, entry->next);
+  INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void
+list_move(struct list_head *list, struct list_head *head)
+{
+  __list_del(list->prev, list->next);
+  list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void
+list_move_tail(struct list_head *list, struct list_head *head)
+{
+  __list_del(list->prev, list->next);
+  list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+  return head->next == head;
+}
+
+static inline void
+__list_splice(struct list_head *list, struct list_head *head)
+{
+  struct list_head *first = list->next;
+  struct list_head *last = list->prev;
+  struct list_head *at = head->next;
+
+  first->prev = head;
+  head->next = first;
+
+  last->next = at;
+  at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void
+list_splice(struct list_head *list, struct list_head *head)
+{
+  if (!list_empty(list))
+    __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void
+list_splice_init(struct list_head *list, struct list_head *head)
+{
+  if (!list_empty(list)) {
+    __list_splice(list, head);
+    INIT_LIST_HEAD(list);
+  }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/main.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,291 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <termios.h>
+
+#include "utils.h"
+#include "screen.h"
+#include "buddies.h"
+#include "parsecfg.h"
+#include "lang.h"
+#include "server.h"
+#include "harddefines.h"
+#include "socket.h"
+
+int sock;
+
+void sig_handler(int signum)
+{
+  switch (signum) {
+  case SIGALRM:
+    sk_send(sock, " ");
+    break;
+
+  case SIGTERM:
+    bud_TerminateBuddies();
+    scr_TerminateCurses();
+    srv_setpresence(sock, "unavailable");
+    close(sock);
+    printf("Killed by SIGTERM\nBye!\n");
+    exit(EXIT_SUCCESS);
+    break;
+
+  }
+  signal(SIGALRM, sig_handler);
+}
+
+ssize_t my_getpass (char **passstr, size_t *n)
+{
+  struct termios orig, new;
+  int nread;
+
+  /* Turn echoing off and fail if we can't. */
+  if (tcgetattr(fileno (stdin), &orig) != 0)
+      return -1;
+  new = orig;
+  new.c_lflag &= ~ECHO;
+  if (tcsetattr(fileno (stdin), TCSAFLUSH, &new) != 0)
+      return -1;
+
+  /* Read the password. */
+  nread = getline(passstr, n, stdin);
+
+  /* Restore terminal. */
+  (void) tcsetattr(fileno (stdin), TCSAFLUSH, &orig);
+
+  return nread;
+}
+
+void credits(void)
+{
+  printf(VERSION "\n");
+  printf(EMAIL "\n");
+}
+
+int main(int argc, char **argv)
+{
+  int i;
+  char configFile[4096];
+  char *buffer;
+  char *secbuffer;
+  char *username, *password, *resource;
+  char *servername;
+  char *idsession;
+  char *portstring;
+  int key;
+  unsigned int port;
+  unsigned int ping;
+
+
+  credits();
+
+  /* SET THIS >0 TO ENABLE LOG */
+  ut_InitDebug(1);
+
+  lng_InitLanguage();
+
+  ut_WriteLog("Setting signals handlers...\n");
+  signal(SIGTERM, sig_handler);
+  signal(SIGALRM, sig_handler);
+
+
+  sprintf(configFile, "%s/.mcabberrc", getenv("HOME"));
+
+  /* Proceso opciones de usuario */
+  while (1) {
+    int c = getopt(argc, argv, "hf:");
+    if (c == -1) {
+      break;
+    } else
+      switch (c) {
+      case 'h':
+	printf("Usage: %s [-f mcabberrc_file]\n\n", argv[0]);
+        printf("Thanks to AjMacias for cabber!\n\n");
+	return 0;
+      case 'f':
+	strncpy(configFile, optarg, 1024);
+	break;
+      }
+  }
+
+  ut_WriteLog("Setting config file: %s\n", configFile);
+
+
+  /* Parsing config file... */
+  ut_WriteLog("Parsing config file...\n");
+  cfg_file(configFile);
+
+  servername = cfg_read("server");
+  username = cfg_read("username");
+  password = cfg_read("password");
+  resource = cfg_read("resource");
+
+  if (!servername) {
+      printf("Server name has not been specified in the config file!\n");
+      return -1;
+  }
+  if (!username) {
+      printf("User name has not been specified in the config file!\n");
+      return -1;
+  }
+  if (!password) {
+      char *p;
+      size_t passsize = 64;
+      printf("Please enter password: ");
+      my_getpass(&password, &passsize);
+      printf("\n");
+      for (p = password; *p; p++);
+      for ( ; p > password ; p--)
+          if (*p == '\n' || *p == '\r') *p = 0;
+  }
+
+  /* Initialize N-Curses */
+  ut_WriteLog("Initializing N-Curses...\n");
+  scr_InitCurses();
+
+  /* Connect to server */
+  portstring = cfg_read("port");
+  port = (portstring != NULL) ? atoi(portstring) : -1;
+
+  ut_WriteLog("Connecting to server: %s:%d\n", servername, port);
+  if ((sock = srv_connect(servername, port)) < 0) {
+    ut_WriteLog("\terror!!!\n");
+    fprintf(stderr, "Error connecting to (%s)\n", servername);
+    scr_TerminateCurses();
+    return -2;
+  }
+
+  ut_WriteLog("Sending login string...\n");
+  if ((idsession = srv_login(sock, servername, username, password, 
+                             resource)) == NULL) {
+
+    ut_WriteLog("\terror!!!\n");
+    fprintf(stderr, "Error sending login string...\n");
+    scr_TerminateCurses();
+    return -3;
+  }
+  ut_WriteLog("Connected to %s: %s\n", servername, idsession);
+  free(idsession);
+
+  ut_WriteLog("Requesting roster...\n");
+  bud_InitBuddies(sock);
+
+  ut_WriteLog("Sending presence...\n");
+  srv_setpresence(sock, "Online!");
+
+
+  ut_WriteLog("Drawing main window...\n");
+  scr_DrawMainWindow();
+
+  ping = 15;
+  if (cfg_read("pinginterval"))
+    ping = atoi(cfg_read("pinginterval"));
+
+  ut_WriteLog("Ping interval stablished: %d secs\n", ping);
+
+  ut_WriteLog("Entering into main loop...\n\n");
+  ut_WriteLog("Ready to send/receive messages...\n");
+  key = 0;
+  while (key != 'x') {
+    int x;
+    alarm(ping);
+    x = check_io(sock, 0);
+    if ((x & 1) == 1) {
+      srv_msg *incoming = readserver(sock);
+
+      switch (incoming->m) {
+      case SM_PRESENCE:
+	bud_SetBuddyStatus(incoming->from, incoming->connected);
+	break;
+
+      case SM_MESSAGE:
+	scr_WriteIncomingMessage(incoming->from, incoming->body);
+	free(incoming->body);
+	free(incoming->from);
+	break;
+
+      case SM_UNHANDLED:
+	break;
+      }
+      free(incoming);
+    }
+    if ((x & 2) == 2) {
+      keypad(scr_GetRosterWindow(), TRUE);
+      key = scr_Getch();
+      switch (key) {
+      case KEY_IC:
+	bud_AddBuddy(sock);
+	break;
+      case KEY_DC:
+	bud_DeleteBuddy(sock);
+	break;
+      case KEY_DOWN:
+	bud_RosterDown();
+	break;
+      case KEY_UP:
+	bud_RosterUp();
+	break;
+
+      case 0x19a:
+	endwin();
+	printf("\nRedimensionado no implementado\n");
+	printf("Reinicie Cabber.\n\n\n");
+	exit(EXIT_FAILURE);
+	break;
+
+      case KEY_NPAGE:
+	for (i = 0; i < 10; i++)
+	  bud_RosterDown();
+	break;
+
+      case KEY_PPAGE:
+	for (i = 0; i < 10; i++)
+	  bud_RosterUp();
+	break;
+
+      case 'z':
+      case KEY_F(1):
+	buffer = (char *) calloc(1, 4096);
+	secbuffer = (char *) calloc(1, 4096);
+
+	sprintf(secbuffer, "INS   = %s ", i18n("Add contact"));
+	i = strlen(secbuffer);
+	strcpy(buffer, secbuffer);
+	sprintf(secbuffer, "DEL   = %s ", i18n("Delete contact"));
+	strcat(buffer, secbuffer);
+	sprintf(secbuffer, "SPACE = %s ", i18n("View buddy window"));
+	strcat(buffer, secbuffer);
+	sprintf(secbuffer, "INTRO = %s ", i18n("Send message"));
+	strcat(buffer, secbuffer);
+	sprintf(secbuffer, "ESC   = %s ", i18n("Exit"));
+	strcat(buffer, secbuffer);
+
+	scr_CreatePopup(i18n("help"), buffer, i, 0, NULL);
+	free(buffer);
+	free(secbuffer);
+	break;
+
+      case '\n':
+	scr_WriteMessage(sock);
+	break;
+
+      case ' ':
+	scr_ShowBuddyWindow();
+	break;
+      }
+    }
+  }
+
+  bud_TerminateBuddies();
+  scr_TerminateCurses();
+
+  srv_setpresence(sock, "unavailable");
+
+  close(sock);
+
+  printf("\n\nHave a nice day!\nBye!\n");
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/parsecfg.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+
+#include "list.h"
+
+/* Definicion de tipos */
+#define MAX_LENGHT_INPUT 1024
+#define cfg_entry(n) list_entry(n, cfg_entry_t, list)
+
+typedef struct _cfg_entry_t {
+  char *key;
+  char *value;
+  struct list_head list;
+} cfg_entry_t;
+
+static LIST_HEAD(cfg_list);
+
+
+void push_in_list(char *key, char *value)
+{
+  cfg_entry_t *new_entry = calloc(1, sizeof(cfg_entry_t));
+
+  new_entry->key = (char *) calloc(1, strlen(key) + 1);
+  new_entry->value = (char *) calloc(1, strlen(value) + 1);
+
+  strcpy(new_entry->key, key);
+  strcpy(new_entry->value, value);
+
+  list_add(&new_entry->list, &cfg_list);
+}
+
+int cfg_file(char *filename)
+{
+  FILE *fp;
+  char *buf;
+  char *line;
+  char *value;
+
+  buf = malloc(255);
+
+  if ((fp = fopen(filename, "r")) == NULL) {
+    perror("fopen (parsecfg.c:46)");
+    exit(EXIT_FAILURE);
+  }
+
+  while (fgets(buf, 255, 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';
+
+      push_in_list(line, value);
+      continue;
+    }
+    fprintf(stderr, "CFG: orphaned line \"%s\"\n", line);
+  }
+  return 1;
+}
+
+char *cfg_read(char *key)
+{
+  struct list_head *n, *pos;
+  cfg_entry_t *search_entry = NULL;
+
+  list_for_each_safe(pos, n, &cfg_list) {
+    search_entry = cfg_entry(pos);
+    if (search_entry->key) {
+      if (!strcasecmp(search_entry->key, key)) {
+	return search_entry->value;
+      }
+    }
+  }
+  return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/parsecfg.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,7 @@
+#ifndef __PARSECFG_H__
+#define __PARSECFG_H__ 1
+
+int cfg_file(char *filename);
+char *cfg_read(char *key);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/screen.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,546 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include <panel.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "screen.h"
+#include "utils.h"
+#include "buddies.h"
+#include "parsecfg.h"
+#include "lang.h"
+#include "server.h"
+
+#include "list.h"
+
+/* Definicion de tipos */
+#define window_entry(n) list_entry(n, window_entry_t, list)
+
+typedef struct _window_entry_t {
+  WINDOW *win;
+  PANEL *panel;
+  char *name;
+  int nlines;
+  char **texto;
+  struct list_head list;
+} window_entry_t;
+
+LIST_HEAD(window_list);
+
+/* Variables globales a SCREEN.C */
+WINDOW *rosterWnd, *chatWnd;
+PANEL *rosterPanel, *chatPanel;
+int maxY, maxX;
+window_entry_t *ventanaActual;
+
+
+/* Funciones */
+
+int scr_WindowHeight(WINDOW * win)
+{
+  int x, y;
+  getmaxyx(win, y, x);
+  return x;
+}
+
+void
+scr_draw_box(WINDOW * win, int y, int x, int height, int width, int Color,
+	     chtype box, chtype border)
+{
+  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++)
+      if (!i && !j)
+	waddch(win, border | ACS_ULCORNER);
+      else if (i == height - 1 && !j)
+	waddch(win, border | ACS_LLCORNER);
+      else if (!i && j == width - 1)
+	waddch(win, box | ACS_URCORNER);
+      else if (i == height - 1 && j == width - 1)
+	waddch(win, box | ACS_LRCORNER);
+      else if (!i)
+	waddch(win, border | ACS_HLINE);
+      else if (i == height - 1)
+	waddch(win, box | ACS_HLINE);
+      else if (!j)
+	waddch(win, border | ACS_VLINE);
+      else if (j == width - 1)
+	waddch(win, box | ACS_VLINE);
+      else
+	waddch(win, box | ' ');
+  }
+}
+
+int FindColor(char *name)
+{
+  if (!strcmp(name, "default"))
+    return -1;
+  if (!strcmp(name, "black"))
+    return COLOR_BLACK;
+  if (!strcmp(name, "red"))
+    return COLOR_RED;
+  if (!strcmp(name, "green"))
+    return COLOR_GREEN;
+  if (!strcmp(name, "yellow"))
+    return COLOR_YELLOW;
+  if (!strcmp(name, "blue"))
+    return COLOR_BLUE;
+  if (!strcmp(name, "magenta"))
+    return COLOR_MAGENTA;
+  if (!strcmp(name, "cyan"))
+    return COLOR_CYAN;
+  if (!strcmp(name, "white"))
+    return COLOR_WHITE;
+
+  return -1;
+}
+
+void ParseColors(void)
+{
+  char *colors[11] = {
+    "", "",
+    "borderlines",
+    "jidonlineselected",
+    "jidonline",
+    "jidofflineselected",
+    "jidoffline",
+    "text",
+    NULL
+  };
+
+  char *tmp = malloc(1024);
+  char *color1;
+  char *background = cfg_read("color_background");
+  char *backselected = cfg_read("color_backselected");
+  int i = 0;
+
+  while (colors[i]) {
+    sprintf(tmp, "color_%s", colors[i]);
+    color1 = cfg_read(tmp);
+
+    switch (i + 1) {
+    case 1:
+      init_pair(1, COLOR_BLACK, COLOR_WHITE);
+      break;
+    case 2:
+      init_pair(2, COLOR_WHITE, COLOR_BLACK);
+      break;
+    case 3:
+      init_pair(3, FindColor(color1), FindColor(background));
+      break;
+    case 4:
+      init_pair(4, FindColor(color1), FindColor(backselected));
+      break;
+    case 5:
+      init_pair(5, FindColor(color1), FindColor(background));
+      break;
+    case 6:
+      init_pair(6, FindColor(color1), FindColor(backselected));
+      break;
+    case 7:
+      init_pair(7, FindColor(color1), FindColor(background));
+      break;
+    case 8:
+      init_pair(8, FindColor(color1), FindColor(background));
+      break;
+    }
+    i++;
+  }
+}
+
+
+window_entry_t *scr_CreatePanel(char *title, int x, int y, int lines,
+				int cols)
+{
+  window_entry_t *tmp = calloc(1, sizeof(window_entry_t));
+
+  tmp->win = newwin(lines, cols, y, x);
+  tmp->panel = new_panel(tmp->win);
+  tmp->name = (char *) calloc(1, 1024);
+  strncpy(tmp->name, title, 1024);
+  scr_draw_box(tmp->win, 0, 0, lines, cols, COLOR_GENERAL, 0, 0);
+  mvwprintw(tmp->win, 0, (cols - (2 + strlen(title))) / 2, " %s ", title);
+
+  list_add_tail(&tmp->list, &window_list);
+  update_panels();
+
+  return tmp;
+}
+
+
+void
+scr_CreatePopup(char *title, char *texto, int corte, int type,
+		char *returnstring)
+{
+  WINDOW *popupWin;
+  PANEL *popupPanel;
+
+  int lineas = 0;
+  int cols = 0;
+
+  char **submsgs;
+  int n = 0;
+  int i;
+
+  char *instr = (char *) calloc(1, 1024);
+
+  /* fprintf(stderr, "\r\n%d", lineas); */
+
+  submsgs = ut_SplitMessage(texto, &n, corte);
+
+  switch (type) {
+  case 1:
+  case 0:
+    lineas = n + 4;
+    break;
+  }
+
+  cols = corte + 3;
+  popupWin = newwin(lineas, cols, (maxY - lineas) / 2, (maxX - cols) / 2);
+  popupPanel = new_panel(popupWin);
+
+  /*ATENCION!!! Colorear el popup ??
+     / box (popupWin, 0, 0); */
+  scr_draw_box(popupWin, 0, 0, lineas, cols, COLOR_POPUP, 0, 0);
+  mvwprintw(popupWin, 0, (cols - (2 + strlen(title))) / 2, " %s ", title);
+
+  for (i = 0; i < n; i++)
+    mvwprintw(popupWin, i + 1, 2, "%s", submsgs[i]);
+
+
+  for (i = 0; i < n; i++)
+    free(submsgs[i]);
+  free(submsgs);
+
+  switch (type) {
+  case 0:
+    mvwprintw(popupWin, n + 2,
+	      (cols - (2 + strlen(i18n("Press any key")))) / 2,
+	      i18n("Press any key"));
+    update_panels();
+    doupdate();
+    getch();
+    break;
+  case 1:
+    {
+      char ch;
+      int scroll = 0;
+      int input_x = 0;
+
+      wmove(popupWin, 3, 1);
+      wrefresh(popupWin);
+      keypad(popupWin, TRUE);
+      while ((ch = getch()) != '\n') {
+	switch (ch) {
+	case 0x09:
+	case KEY_UP:
+	case KEY_DOWN:
+	  break;
+	case KEY_RIGHT:
+	case KEY_LEFT:
+	  break;
+	case KEY_BACKSPACE:
+	case 127:
+	  if (input_x || scroll) {
+	    /* wattrset (popupWin, 0); */
+	    if (!input_x) {
+	      scroll = scroll < cols - 3 ? 0 : scroll - (cols - 3);
+	      wmove(popupWin, 3, 1);
+	      for (i = 0; i < cols; i++)
+		waddch
+		    (popupWin,
+		     instr
+		     [scroll
+		      + input_x + i] ? instr[scroll + input_x + i] : ' ');
+	      input_x = strlen(instr) - scroll;
+	    } else
+	      input_x--;
+	    instr[scroll + input_x] = '\0';
+	    mvwaddch(popupWin, 3, input_x + 1, ' ');
+	    wmove(popupWin, 3, input_x + 1);
+	    wrefresh(popupWin);
+	  }
+	default:
+	  if ( /*ch<0x100 && */ isprint(ch) || ch == 'ñ'
+	      || ch == 'Ñ') {
+	    if (scroll + input_x < 1024) {
+	      instr[scroll + input_x] = ch;
+	      instr[scroll + input_x + 1] = '\0';
+	      if (input_x == cols - 3) {
+		scroll++;
+		wmove(popupWin, 3, 1);
+		for (i = 0; i < cols - 3; i++)
+		  waddch(popupWin, instr[scroll + i]);
+	      } else {
+		wmove(popupWin, 3, 1 + input_x++);
+		waddch(popupWin, ch);
+	      }
+	      wrefresh(popupWin);
+	    } else {
+	      flash();
+	    }
+	  }
+	}
+      }
+    }
+    if (returnstring != NULL)
+      strcpy(returnstring, instr);
+    break;
+  }
+
+  del_panel(popupPanel);
+  delwin(popupWin);
+  update_panels();
+  doupdate();
+  free(instr);
+  keypad(rosterWnd, TRUE);
+}
+
+
+
+void scr_RoolWindow(void)
+{
+}
+
+window_entry_t *scr_SearchWindow(char *nombreVentana)
+{
+  struct list_head *pos, *n;
+  window_entry_t *search_entry = NULL;
+
+  list_for_each_safe(pos, n, &window_list) {
+    search_entry = window_entry(pos);
+    if (search_entry->name) {
+      if (!strcasecmp(search_entry->name, nombreVentana)) {
+	return search_entry;
+      }
+    }
+  }
+  return NULL;
+}
+
+void scr_ShowWindow(char *nombreVentana)
+{
+  int n, width, i;
+  window_entry_t *tmp = scr_SearchWindow(nombreVentana);
+  if (tmp != NULL) {
+    top_panel(tmp->panel);
+    width = scr_WindowHeight(tmp->win);
+    for (n = 0; n < tmp->nlines; n++) {
+      mvwprintw(tmp->win, n + 1, 1, "");
+      for (i = 0; i < width - 2; i++)
+	waddch(tmp->win, ' ');
+      mvwprintw(tmp->win, n + 1, 1, "%s", tmp->texto[n]);
+    }
+    move(maxY - 2, maxX - 1);
+    update_panels();
+    doupdate();
+  }
+}
+
+void scr_ShowBuddyWindow(void)
+{
+  buddy_entry_t *tmp = bud_SelectedInfo();
+  if (tmp->jid != NULL)
+    scr_ShowWindow(tmp->jid);
+}
+
+
+void scr_WriteInWindow(char *nombreVentana, char *texto, int TimeStamp)
+{
+  time_t ahora;
+  int n;
+  int i;
+  int width;
+  window_entry_t *tmp;
+
+  tmp = scr_SearchWindow(nombreVentana);
+  if (tmp == NULL) {
+    tmp = scr_CreatePanel(nombreVentana, 20, 0, maxY-1, maxX - 20);
+    tmp->texto = (char **) calloc(maxY * 3, sizeof(char *));
+    for (n = 0; n < (maxY-1) * 3; n++)
+      tmp->texto[n] = (char *) calloc(1, 1024);
+
+    if (TimeStamp) {
+      ahora = time(NULL);
+      strftime(tmp->texto[tmp->nlines], 1024, "[%H:%M] ",
+	       localtime(&ahora));
+      strcat(tmp->texto[tmp->nlines], texto);
+    } else {
+      sprintf(tmp->texto[tmp->nlines], "            %s", texto);
+    }
+    tmp->nlines++;
+  } else {
+    if (tmp->nlines < maxY - 3) {
+      if (TimeStamp) {
+	ahora = time(NULL);
+	strftime(tmp->texto[tmp->nlines], 1024,
+		 "[%H:%M] ", localtime(&ahora));
+	strcat(tmp->texto[tmp->nlines], texto);
+      } else {
+	sprintf(tmp->texto[tmp->nlines], "            %s", texto);
+      }
+      tmp->nlines++;
+    } else {
+      for (n = 0; n < tmp->nlines; n++) {
+	memset(tmp->texto[n], 0, 1024);
+	strncpy(tmp->texto[n], tmp->texto[n + 1], 1024);
+      }
+      if (TimeStamp) {
+	ahora = time(NULL);
+	strftime(tmp->texto[tmp->nlines - 1], 1024,
+		 "[%H:%M] ", localtime(&ahora));
+	strcat(tmp->texto[tmp->nlines - 1], texto);
+      } else {
+	sprintf(tmp->texto[tmp->nlines - 1], "            %s", texto);
+      }
+    }
+  }
+
+  top_panel(tmp->panel);
+  width = scr_WindowHeight(tmp->win);
+  for (n = 0; n < tmp->nlines; n++) {
+    mvwprintw(tmp->win, n + 1, 1, "");
+    for (i = 0; i < width - 2; i++)
+      waddch(tmp->win, ' ');
+    mvwprintw(tmp->win, n + 1, 1, "%s", tmp->texto[n]);
+  }
+
+  update_panels();
+  doupdate();
+}
+
+void scr_InitCurses(void)
+{
+  initscr();
+  noecho();
+  raw();
+  start_color();
+  use_default_colors();
+
+  ParseColors();
+
+  getmaxyx(stdscr, maxY, maxX);
+
+  return;
+}
+
+void scr_DrawMainWindow(void)
+{
+  /* Dibujamos los paneles principales */
+  rosterWnd = newwin(maxY-1, 20, 0, 0);
+  rosterPanel = new_panel(rosterWnd);
+  scr_draw_box(rosterWnd, 0, 0, maxY-1, 20, COLOR_GENERAL, 0, 0);
+  mvwprintw(rosterWnd, 0, (20 - strlen(i18n("Roster"))) / 2,
+	    i18n("Roster"));
+
+  chatWnd = newwin(maxY-1, maxX - 20, 0, 20);
+  chatPanel = new_panel(chatWnd);
+  scr_draw_box(chatWnd, 0, 0, maxY-1, maxX - 20, COLOR_GENERAL, 0, 0);
+  mvwprintw(chatWnd, 0,
+	    ((maxX - 20) - strlen(i18n("Status Window"))) / 2,
+	    i18n("Status Window"));
+
+  bud_DrawRoster(rosterWnd);
+
+  update_panels();
+  doupdate();
+  return;
+}
+
+void scr_TerminateCurses(void)
+{
+  clear();
+  refresh();
+  endwin();
+  return;
+}
+
+void scr_WriteIncomingMessage(char *jidfrom, char *text)
+{
+  char **submsgs;
+  int n, i;
+  char *buffer = (char *) malloc(5 + strlen(text));
+
+  sprintf(buffer, "<<< %s", text);
+
+  submsgs =
+      ut_SplitMessage(buffer, &n, maxX - scr_WindowHeight(rosterWnd) - 20);
+
+  for (i = 0; i < n; i++) {
+    if (i == 0)
+      scr_WriteInWindow(jidfrom, submsgs[i], TRUE);
+    else
+      scr_WriteInWindow(jidfrom, submsgs[i], FALSE);
+  }
+
+  for (i = 0; i < n; i++)
+    free(submsgs[i]);
+
+  free(submsgs);
+  free(buffer);
+
+}
+
+void scr_WriteMessage(int sock)
+{
+  char **submsgs;
+  int n, i;
+  char *buffer = (char *) calloc(1, 1024);
+  char *buffer2 = (char *) calloc(1, 1024);
+  buddy_entry_t *tmp = bud_SelectedInfo();
+
+  scr_ShowWindow(tmp->jid);
+
+  ut_CenterMessage(i18n("write your message here"), 60, buffer2);
+
+  scr_CreatePopup(tmp->jid, buffer2, 60, 1, buffer);
+
+  if (strlen(buffer)) {
+    sprintf(buffer2, ">>> %s", buffer);
+
+    submsgs =
+	ut_SplitMessage(buffer2, &n,
+			maxX - scr_WindowHeight(rosterWnd) - 20);
+    for (i = 0; i < n; i++) {
+      if (i == 0)
+	scr_WriteInWindow(tmp->jid, submsgs[i], TRUE);
+      else
+	scr_WriteInWindow(tmp->jid, submsgs[i], FALSE);
+    }
+
+    for (i = 0; i < n; i++)
+      free(submsgs[i]);
+    free(submsgs);
+
+    move(maxY - 2, maxX - 1);
+    refresh();
+    sprintf(buffer2, "%s@%s/%s", cfg_read("username"),
+	    cfg_read("server"), cfg_read("resource"));
+    srv_sendtext(sock, tmp->jid, buffer, buffer2);
+  }
+  free(buffer);
+  free(buffer2);
+}
+
+int scr_Getch(void)
+{
+  int ch;
+  keypad(rosterWnd, TRUE);
+  ch = wgetch(rosterWnd);
+  return ch;
+}
+
+WINDOW *scr_GetRosterWindow(void)
+{
+  return rosterWnd;
+}
+
+WINDOW *scr_GetStatusWindow(void)
+{
+  return chatWnd;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/screen.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,30 @@
+#ifndef __SCREEN_H__
+#define __SCREEN_H__ 1
+
+#include <ncurses.h>
+
+#define COLOR_POPUP     1
+#define COLOR_GENERAL   3
+#define COLOR_BD_CONSEL 4
+#define COLOR_BD_CON    5
+#define COLOR_BD_DESSEL 6
+#define COLOR_BD_DES    7
+
+void scr_InitCurses(void);
+void scr_DrawMainWindow(void);
+void scr_TerminateCurses(void);
+void scr_CreatePopup(char *title, char *texto, int corte, int type,
+		     char *returnstring);
+void scr_WriteInWindow(char *nombreVentana, char *texto, int TimeStamp);
+void scr_WriteMessage(int sock);
+void scr_WriteIncomingMessage(char *jidfrom, char *text);
+void scr_RoolWindow(void);
+void scr_ShowBuddyWindow(void);
+
+WINDOW *scr_GetRosterWindow(void);
+WINDOW *scr_GetStatusWindow(void);
+
+int scr_Getch(void);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/server.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,459 @@
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+
+#include "list.h"
+#include "parsecfg.h"
+#include "screen.h"
+#include "socket.h"
+#include "utf8.h"
+#include "server.h"
+#include "harddefines.h"
+#include "utils.h"
+#include "buddies.h"
+
+#define JABBERPORT 5222
+
+
+/* Desc: poll data from server
+ * 
+ * In  : socket
+ * Out : pending buffer (or NULL if no incoming data)
+ *
+ * Note: it is up to the caller to free the returned string
+ */
+char *srv_poll(int sock)
+{
+  struct pollfd sock_p;
+  sock_p.fd = sock;
+  sock_p.events = POLLIN | POLLPRI;
+  sock_p.revents = 0;
+  poll(&sock_p, 1, 0);
+
+  if (sock_p.revents) {
+    return sk_recv(sock);
+  }
+
+  return NULL;
+}
+
+
+/* Desc: resolve host
+ * 
+ * In  : hostname
+ * Out : 32bit address (or 0 if error)
+ *
+ * Note: -
+ */
+static u_long srv_resolve(const char *host)
+{
+  long i;
+  struct hostent *he;
+
+  if ((i = inet_addr(host)) == -1) {
+    if (!(he = gethostbyname(host)))
+      return 0;
+    else
+      return (*(u_long *) he->h_addr);
+  }
+
+  return i;
+}
+
+
+/* Desc: connect to jabber server
+ * 
+ * In  : config
+ * Out : socket (or -1 on error)
+ *
+ * Note: if port is -1, the default Jabber port will be used
+ */
+int srv_connect(const char *server, unsigned int port)
+{
+  struct sockaddr_in name;
+  int sock;
+
+  if (server == NULL) {
+    fprintf(stderr, "You must supply a server name\n\r");
+    return -1;
+  }
+
+  if (port == -1U) {
+    port = JABBERPORT;
+  }
+
+  name.sin_family = AF_INET;
+  name.sin_port = htons(port);
+
+  if (!(name.sin_addr.s_addr = srv_resolve(server))) {
+    fprintf(stderr, "Cant resolve \"%s\"\n", server);
+    return -1;
+  }
+
+  if ((sock = sk_conn((struct sockaddr *) &name)) < 0) {
+    fprintf(stderr, "Cant connect to \"%s:%u\"\n", server, port);
+    return -1;
+  }
+
+  return sock;
+}
+
+
+/* Desc: login into jabber server
+ * 
+ * In  : socket, servername, user, password, resource
+ * Out : idsession
+ *
+ * Note: it is up to the caller to free the returned string
+ */
+char *srv_login(int sock, const char *server, const char *user,
+		const char *pass, const char *resource)
+{
+  char *stringtosend = malloc(2048);
+  char *response, *aux;
+  char *idsession = malloc(128);
+  int pos = 0;
+
+  memset(stringtosend, 0, 2048);
+  strcpy(stringtosend, "<?xml version='1.0' encoding='UTF-8' ?>");
+  strcat(stringtosend, "<stream:stream to='");
+  strcat(stringtosend, server);
+  strcat(stringtosend, "' xmlns='jabber:client' xmlns:stream='");
+  strcat(stringtosend, "http://etherx.jabber.org/streams'>\n");
+
+  if (!sk_send(sock, stringtosend)) {
+    perror("senddata (server.c:132)");
+    return NULL;
+  }
+  response = sk_recv(sock);
+  if (strstr(response, "error")) {
+    /* fprintf(stderr, "Response not valid:\n%s\n\n", response); */
+    scr_CreatePopup("Error",
+		    "El servidor no esta respondiendo correctamente",
+		    60, 0, NULL);
+    return NULL;
+  }
+  aux = response;
+  while (strncmp(aux, "id", 2))
+    aux++;
+  pos = 0;
+  aux += 4;
+  while (strncmp(aux, "'", 1)) {
+    aux++;
+    pos++;
+  }
+  aux -= pos;
+  strncpy(idsession, aux, pos);
+
+  free(response);
+
+  strcpy(stringtosend, "<iq type='set' id='1000'>");
+  strcat(stringtosend, "<query xmlns='jabber:iq:auth'>");
+  strcat(stringtosend, "<username>");
+  strcat(stringtosend, user);
+  strcat(stringtosend, "</username><password>");
+  strcat(stringtosend, pass);
+  strcat(stringtosend, "</password><resource>");
+  strcat(stringtosend, resource);
+  strcat(stringtosend, "</resource></query></iq>\n");
+  if (!sk_send(sock, stringtosend)) {
+    perror("senddata (server.c:167)");
+    return NULL;
+  }
+  response = sk_recv(sock);
+  if (strstr(response, "error")) {
+/*	fprintf(stderr, "Response not valid:\n%s\n\n", response);*/
+    scr_CreatePopup("Error",
+		    "Cuenta no creada o contraseña incorrecta", 60, 0,
+		    NULL);
+    scr_CreatePopup("Info", "Intentando crear la cuenta...", 60, 0, NULL);
+
+
+    strcpy(stringtosend, "<iq type='set' id='reg' to='");
+    strcat(stringtosend, server);
+    strcat(stringtosend, "'>");
+    strcat(stringtosend, "<query xmlns='jabber:iq:register'>");
+    strcat(stringtosend, "<username>");
+    strcat(stringtosend, user);
+    strcat(stringtosend, "</username><password>");
+    strcat(stringtosend, pass);
+    strcat(stringtosend, "</password>");
+    strcat(stringtosend, "</query></iq>\n");
+    if (!sk_send(sock, stringtosend)) {
+      perror("senddata (server.c:167)");
+      return NULL;
+    }
+
+    response = sk_recv(sock);
+    scr_TerminateCurses();
+    printf("Reinicie cabber!\n\n");
+    return NULL;
+  }
+  free(response);
+  free(stringtosend);
+
+  return idsession;
+}
+
+
+/* Desc: broadcast presence
+ * 
+ * In  : socket, presence string
+ * Out : ?
+ *
+ * Note: see `sk_send' for output values
+ */
+int srv_setpresence(int sock, const char *type)
+{
+  int rv;
+  char *str = malloc(1024);
+
+  sprintf(str, "<presence><status>%s</status></presence>", type);
+  if (!(rv = sk_send(sock, str))) {
+    perror("senddata (server.c:199)");
+  }
+  free(str);
+
+  return rv;
+}
+
+
+/* Desc: request roster
+ * 
+ * In  : socket
+ * Out : roster string
+ *
+ * Note: it is up to the caller to free the returned string
+ */
+char *srv_getroster(int sock)
+{
+  char *str = malloc(1024);
+
+  strcpy(str, "<iq type='get' id='1001'><query xmlns='");
+  strcat(str, "jabber:iq:roster'/></iq>\n");
+  if (!sk_send(sock, str)) {
+    perror("senddata (server.c:222)");
+    return NULL;
+  }
+  free(str);
+
+  return sk_recv(sock);
+}
+
+
+/* Desc: send text to buddy
+ * 
+ * In  : socket, destination jid, text, source jid
+ * Out : 0 = ok
+ *
+ * Note: -
+ */
+int
+srv_sendtext(int sock, const char *to, const char *text, const char *from)
+{
+  char *stringtosend = malloc(2048);
+  char *utf8inputline = utf8_encode(text);
+
+  sprintf(stringtosend,
+	  "<message from='%s' to='%s' type='chat'><body>%s</body></message>",
+	  from, to, utf8inputline);
+  if (!sk_send(sock, stringtosend)) {
+    perror("senddata (server.c:247)");
+    return -1;
+  }
+
+  free(stringtosend);
+  free(utf8inputline);
+  return 0;
+}
+
+int check_io(int fd1, int fd2)
+{
+  int n = 0, i;
+  fd_set fds;
+  int io_pending = 0;
+
+  i = fd1;
+  if (fd2 > fd1)
+    i = fd2;
+
+  FD_ZERO(&fds);
+  if (fd1 >= 0)
+    FD_SET(fd1, &fds);
+  else
+    fd1 = 0;
+  if (fd2 >= 0)
+    FD_SET(fd2, &fds);
+  else
+    fd2 = 0;
+
+  if (fd2 == 0 && io_pending)
+    n = 2;
+  else if (select(i + 1, &fds, NULL, NULL, NULL) > 0)
+    n = 1 * (FD_ISSET(fd1, &fds) > 0) + 2 * (FD_ISSET(fd2, &fds) > 0);
+
+  return (n);
+}
+
+/* Desc: read data from server
+ *
+ * In  : socket
+ * Out : ptr to newly allocated srv_msg struct
+ *
+ * Note: returns NULL if no input from server
+ */
+srv_msg *readserver(int sock)
+{
+  char *buffer = sk_recv(sock);
+
+  if (buffer != NULL) {
+    srv_msg *msg = calloc(1, sizeof(srv_msg));
+    char *to = getattr(buffer, "to='");
+    char *from = getattr(buffer, "from='");
+    char *id = getattr(buffer, "id='");
+    char *type = getattr(buffer, "type='");
+    char *body = gettag(buffer, "body");
+    char *status = gettag(buffer, "status");
+    char *show = gettag(buffer, "show");
+    char *line = (char *) malloc(1024);
+    memset(line, 0, 1024);
+
+    /* scan for buffer */
+    if (!strncmp(buffer, "<message", 8)) {	/* manage messages */
+      msg->m = SM_MESSAGE;
+    } else if (!strncmp(buffer, "<presence", 9)) {	/* manage presences */
+      msg->m = SM_PRESENCE;
+      if (!strncmp(type, "UNK", 3)) {	/* assume online */
+	msg->connected = FLAG_BUDDY_CONNECTED;
+      } else if (!strncmp(type, "unavailable", 11)) {	/* offline */
+	msg->connected = 0;
+      }
+    } else {
+      msg->m = SM_UNHANDLED;
+    }
+
+    /* write the parsed buffer */
+    switch (msg->m) {
+    case SM_MESSAGE:
+      {
+	char *aux = strstr(from, "/");
+	if (aux)
+	  *aux = '\0';
+	msg->from = from;
+	msg->body = utf8_decode(body);
+	ut_WriteLog("+OK [%s]\n", buffer);
+      }
+      break;
+
+    case SM_PRESENCE:
+      {
+	char *aux = strstr(from, "/");
+	if (aux)
+	  *aux = '\0';
+	msg->from = from;
+      }
+      break;
+
+    case SM_UNHANDLED:
+      ut_WriteLog("BAD [%s]\n", buffer);
+      break;
+
+    }
+    free(line);
+    if (strncmp(to, "UNK", 3))
+      free(to);
+    if (strncmp(from, "UNK", 3) && (msg->m != SM_MESSAGE)
+	&& (msg->m != SM_PRESENCE))
+      free(from);
+    if (strncmp(id, "UNK", 3))
+      free(id);
+    if (strncmp(type, "UNK", 3))
+      free(type);
+    if (strncmp(body, "UNK", 3))
+      free(body);
+    if (strncmp(status, "UNK", 3))
+      free(status);
+    if (strncmp(show, "UNK", 3))
+      free(show);
+    free(buffer);
+
+    return msg;
+  }
+
+  return NULL;
+}
+
+void srv_AddBuddy(int sock, char *jidname)
+{
+  char *buffer = (char *) malloc(1024);
+  char *p, *str;
+  int i;
+
+  memset(buffer, 0, 1024);
+  strcpy(buffer, "<iq type='set'>");
+  strcat(buffer, "  <query xmlns='jabber:iq:roster'>");
+  strcat(buffer, "    <item");
+  strcat(buffer, "      jid='");
+  strcat(buffer, jidname);
+  strcat(buffer, "' name='");
+
+  str = strdup(jidname);
+  p = strstr(str, "@");
+  if (p)
+    *p = '\0';
+  strcat(buffer, str);
+  strcat(buffer, "'/></query></iq>");
+  sk_send(sock, buffer);
+  free(buffer);
+
+  for (i = 0; i < 2; i++) {
+    buffer = sk_recv(sock);
+    ut_WriteLog("[Subscription]: %s\n", buffer);
+    free(buffer);
+  }
+
+  buffer = (char *) malloc(1024);
+  memset(buffer, 0, 1024);
+  strcpy(buffer, "<presence to='");
+  strcat(buffer, jidname);
+  strcat(buffer, "' type='subscribe'>");
+  strcat(buffer, "<status>I would like to add you!</status></presence>");
+  sk_send(sock, buffer);
+  free(buffer);
+
+  buffer = sk_recv(sock);
+  ut_WriteLog("[Subscription]: %s\n", buffer);
+  free(buffer);
+
+  buffer = (char *) malloc(1024);
+  memset(buffer, 0, 1024);
+  strcpy(buffer, "<presence to='");
+  strcat(buffer, jidname);
+  strcat(buffer, "' type='subscribed'/>");
+  sk_send(sock, buffer);
+  free(buffer);
+
+  buffer = sk_recv(sock);
+  ut_WriteLog("[Subscription]: %s\n", buffer);
+  free(buffer);
+}
+
+void srv_DelBuddy(int sock, char *jidname)
+{
+  char *buffer = (char *) malloc(1024);
+
+  strcpy(buffer, "<iq type='set'><query xmlns='jabber:iq:roster'>");
+  strcat(buffer, "<item jid='");
+  strcat(buffer, jidname);
+  strcat(buffer, "' subscription='remove'/></query></iq>");
+
+  sk_send(sock, buffer);
+  free(buffer);
+
+  buffer = sk_recv(sock);
+  ut_WriteLog("[SubscriptionRemove]: %s\n", buffer);
+  free(buffer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/server.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,29 @@
+#ifndef __SERVER_H__
+#define __SERVER_H__ 1
+
+typedef enum {
+  SM_MESSAGE,
+  SM_PRESENCE,
+  SM_UNHANDLED
+} SRV_MSGTYPE;
+
+typedef struct {
+  SRV_MSGTYPE m;		/* message type: see above! */
+  int connected;		/* meaningful only with SM_PRESENCE */
+  char *from;			/* sender */
+  char *body;			/* meaningful only with SM_MESSAGE */
+} srv_msg;
+
+char *srv_poll(int sock);
+int srv_connect(const char *server, unsigned int port);
+char *srv_login(int sock, const char *server, const char *user,
+		const char *pass, const char *resource);
+int srv_setpresence(int sock, const char *type);
+char *srv_getroster(int sock);
+int srv_sendtext(int sock, const char *to, const char *text,
+		 const char *from);
+int check_io(int fd1, int fd2);
+srv_msg *readserver(int sock);
+void srv_DelBuddy(int sock, char *jidname);
+void srv_AddBuddy(int sock, char *jidname);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/socket.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include "utils.h"
+
+#include "socket.h"
+#include <signal.h>
+
+/* Desc: create socket connection
+ * 
+ * In  : servername, port
+ * Out : socket (or -1 on error)
+ *
+ * Note: -
+ */
+int sk_conn(struct sockaddr *name)
+{
+  int sock;
+
+  if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+    perror("socket (socket.c:23)");
+    return -1;
+  }
+
+  if (connect(sock, (struct sockaddr *) name, sizeof(struct sockaddr)) < 0) {
+    perror("connect (socket.c:29)");
+    return -1;
+  }
+
+  return sock;
+}
+
+
+/* Desc: send data through socket
+ * 
+ * In  : socket, buffer to send
+ * Out : 0 = fail, 1 = pass
+ *
+ * Note: -
+ */
+int sk_send(int sock, char *buffer)
+{
+  if ((send(sock, buffer, strlen(buffer), 0)) == -1)
+    return 0;
+  else
+    return 1;
+}
+
+/* Desc: receive data through socket
+ * 
+ * In  : socket
+ * Out : received buffer
+ *
+ * Note: it is up to the caller to free the returned string
+ */
+char *sk_recv(int sock)
+{
+  int i = 1;
+  int tambuffer = 128;
+  char mtag[16];
+
+  char *buffer = malloc(tambuffer);
+  char *retval = malloc(tambuffer + 1);
+
+  memset(retval, 0, tambuffer);
+  memset(buffer, 0, tambuffer + 1);
+
+  while (1) {
+    char *p1;
+    recv(sock, buffer, tambuffer, 0);
+
+    if (i == 1) {
+      char *p2;
+      strcpy(retval, buffer);
+      p1 = retval+1;
+      p2 = mtag;
+      while (('a' <= *p1) && (*p1 <= 'z') && (p2-mtag < 14))
+        *p2++ = *p1++;
+      *p2++ = '>'; *p2++ = 0;
+      //fprintf(stderr, "TAG=\"%s\"\n", mtag);
+    } else {
+      retval = realloc(retval, (tambuffer * i) + 1);
+      strncat(retval, buffer, tambuffer + 1);
+    }
+    i++;
+    p1 = retval + strlen(retval) - strlen(mtag);
+    //fprintf(stderr, "buffer:[%s]\n", buffer);
+    //fprintf(stderr, "End RET=[%s]\n", p1);
+    if (!strcmp(p1, mtag))
+      break;
+    for (p1 = retval; *p1 && (*p1 != '>'); p1++);
+    if ((*p1 == '>') && (*(p1-1) == '/'))
+      break;
+    memset(buffer, 0, tambuffer);
+  }
+  free(buffer);
+  ut_WriteLog("Received:%s\n", retval);
+  return retval;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/socket.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,10 @@
+#ifndef __SOCKET_H__
+#define __SOCKET_H__ 1
+
+#include <sys/socket.h>
+
+int sk_conn(struct sockaddr *name);
+int sk_send(int sock, char *buffer);
+char *sk_recv(int sock);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/utf8.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+
+
+/* Desc: convert UTF8 -> ASCII
+ * 
+ * In  : UTF8 string
+ * Out : ASCII string
+ *
+ * Note: it is up to the caller to free the returned string
+ */
+char *utf8_decode(const char *src)
+{
+  char *ret = calloc(1, strlen(src) + 1);
+  char *aux = ret;
+
+  while (*src) {
+    unsigned char lead = *src++;
+    if ((lead & 0xe0) == 0xc0) {
+      unsigned char ch2 = *src++;
+      *aux = ((lead & 0x1f) << 6) | (ch2 & 0x3f);
+    } else {
+      *aux = lead;
+    }
+    aux++;
+  }
+
+  return ret;
+}
+
+
+/* Desc: convert ASCII -> UTF8
+ * 
+ * In  : ASCII string
+ * Out : UTF8 string
+ *
+ * Note: it is up to the caller to free the returned string
+ */
+char *utf8_encode(const char *src)
+{
+  char *ret = calloc(1, (strlen(src) * 2) + 1);
+  char *aux = ret;
+
+  while (*src) {
+    unsigned char ch = *src++;
+    if (ch < 0x80) {
+      *aux = ch;
+    } else {			/* if (ch < 0x800) { */
+      *aux++ = 0xc0 | (ch >> 6 & 0x1f);
+      *aux = 0xc0 | (0x80 | (ch & 0x3f));
+    }
+    aux++;
+  }
+
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/utf8.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,7 @@
+#ifndef __UTF8_H__
+#define __UTF8_H__ 1
+
+char *utf8_decode(const char *src);
+char *utf8_encode(const char *src);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/utils.c	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,191 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <stdarg.h>
+#include <time.h>
+
+/* Variables globales a UTILS.C */
+int DebugEnabled = 0;
+
+void ut_InitDebug(int level)
+{
+  FILE *fp = fopen("/tmp/mcabberlog", "w");
+
+  DebugEnabled = level;
+  fprintf(fp, "Debug inicializado...\n"
+	  "-----------------------------------\n");
+  fclose(fp);
+}
+
+void ut_WriteLog(const char *fmt, ...)
+{
+  FILE *fp = NULL;
+  time_t ahora;
+  va_list ap;
+  char *buffer = NULL;
+
+  if (DebugEnabled) {
+    fp = fopen("/tmp/mcabberlog", "a+");
+    buffer = (char *) calloc(1, 8192);
+
+    ahora = time(NULL);
+    strftime(buffer, 1024, "[%H:%M:%S] ", localtime(&ahora));
+    fprintf(fp, "%s", buffer);
+
+    va_start(ap, fmt);
+    vfprintf(fp, fmt, ap);
+    va_end(ap);
+
+    free(buffer);
+    fclose(fp);
+  }
+}
+
+char **ut_SplitMessage(char *mensaje, int *nsubmsgs, unsigned int maxlong)
+{
+  /* BUGs:    recorta la palabra si la longitud maxlong es menor que la palabra
+     //  maxlong = 4
+     // mensaje = "peaso bug!"
+     // submsgs[0] = "peas"
+     // submsgs[1] = "bug!"
+     // por lo demas, rula de arte. De todos modos, podrias verificarla ???
+   */
+  char *running;
+  char *aux;
+  char *aux2;
+  char **submsgs;
+  char *buffer = (char *) malloc(strlen(mensaje) * 2);
+  int i = 0;
+
+  submsgs = (char **) malloc(50 * sizeof(char *));	/* limitamos, a priori, el maximo de lineas devueltas... */
+
+  running = strdup(mensaje);	/* duplicamos mensaje */
+  aux2 = strdup(mensaje);	/* hacemos otra copia */
+  while (strlen(aux2) > maxlong) {	/* mintras quede texto... */
+    memset(buffer, 0, strlen(mensaje) * 2);	/* borramos el buffer */
+    running[maxlong] = '\0';	/* cortamos la cadena a la maxima longitud */
+    aux = rindex(running, ' ');	/* posicion del ultimo blanco */
+    if (aux != NULL)		/* hay blanco! */
+      strncpy(buffer, running, strlen(running) - strlen(aux));
+    else
+      strcpy(buffer, running);	/* se supone que esto es pa evitar  el bug explicado arriba, pero no rula */
+
+    submsgs[i] = (char *) malloc(strlen(buffer) + 1);	/*reservamos memoria */
+    strcpy(submsgs[i], buffer);	/*copiamos el buffer de arriba */
+    i++;			/*aumentamos numero de mensajillos */
+    aux2 += strlen(buffer) + 1;	/*eliminamos texto particionado */
+    sprintf(running, "%s", aux2);	/*y lo copiamos de nuevo a la string de "curro" */
+  }
+  /* la ultima parte del mensaje, si la hay ;-) */
+  if (strlen(aux2) > 0) {
+    submsgs[i] = (char *) malloc(strlen(aux2) + 1);
+    strcpy(submsgs[i], aux2);
+    i++;
+  }
+  (*nsubmsgs) = i;
+  free(buffer);
+  return submsgs;
+}
+
+/* Desc: get the rightmost substring
+ *
+ * In  : string, match
+ * Out : ptr to substring (or NULL if not found)
+ *
+ * Note: this one has no namespace, cos it belongs to <string.h>
+ */
+char *ut_strrstr(const char *s1, const char *s2)
+{
+  int l = strlen(s2);
+
+  if (l) {
+    const char *s = strchr(s1, '\0') - l;
+    while (s >= s1) {
+      if (*s == *s2) {
+	int _l = l - 1;
+	const char *_s = s + 1, *_s2 = s2 + 1;
+	while (_l) {
+	  if (*_s++ != *_s2++) {
+	    break;
+	  }
+	  _l--;
+	}
+	if (!_l) {
+	  return (char *) s;
+	}
+      }
+      s--;
+    }
+  }
+
+  return NULL;
+}
+
+char *gettag(char *buffer, char *what)
+{
+  char *aux;
+  char *aux2;
+  char *result = (char *) malloc(1024);
+  char *tmp = (char *) malloc(1024);
+  memset(result, 0, 1024);
+  memset(tmp, 0, 1024);
+
+  sprintf(tmp, "<%s>", what);
+  aux = strstr(buffer, tmp);
+  if (aux) {
+    aux += strlen(tmp);
+    sprintf(tmp, "</%s>", what);
+    aux2 = strstr(aux, tmp);
+    if (aux2) {
+      strncpy(result, aux, strlen(aux) - strlen(aux2));
+      free(tmp);
+      return result;
+    }
+  }
+  free(tmp);
+  free(result);
+  return "UNKtag";
+}
+
+
+char *getattr(char *buffer, char *what)
+{
+  char *aux;
+  char *aux2;
+  char *result = (char *) malloc(1024);
+  memset(result, 0, 1024);
+
+  aux = strstr(buffer, what);
+  if (aux) {
+    aux += strlen(what);
+    aux2 = strstr(aux, "'");
+    if (aux2) {
+      strncpy(result, aux, strlen(aux) - strlen(aux2));
+      return result;
+    }
+  }
+  free(result);
+  return "UNKattr";
+}
+
+void ut_CenterMessage(char *text, int width, char *output)
+{
+  char *blank;
+  int ntest, nn;
+
+  memset(output, 0, strlen(output));
+
+  ntest = (width - strlen(text)) / 2;
+  blank = (char *) malloc(ntest + 1);
+
+  for (nn = 0; nn < ntest; nn++)
+    blank[nn] = ' ';
+  blank[ntest] = '\0';
+
+  strcpy(output, blank);
+  strcat(output, text);
+  strcat(output, blank);
+
+  free(blank);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcabber/utils.h	Thu Jun 30 21:39:31 2005 +0000
@@ -0,0 +1,16 @@
+#ifndef __UTILS_H__
+#define __UTILS_H__ 1
+
+#include <ncurses.h>
+
+char **ut_SplitMessage(char *mensaje, int *nsubmsgs, unsigned int maxlong);
+void ut_InitDebug(int level);
+void ut_WriteLog(const char *fmt, ...);
+char *ut_strrstr(const char *s1, const char *s2);
+char *getattr(char *buffer, char *what);
+char *gettag(char *buffer, char *what);
+void ut_CenterMessage(char *text, int width, char *output);
+
+
+
+#endif