[Pkg-silc-commits] r39 - in /si: ./ branches/ branches/upstream/ branches/upstream/current/ branches/upstream/current/contrib/ tags/

stesie-guest at users.alioth.debian.org stesie-guest at users.alioth.debian.org
Mon May 28 17:37:58 UTC 2007


Author: stesie-guest
Date: Mon May 28 17:37:58 2007
New Revision: 39

URL: http://svn.debian.org/wsvn/pkg-silc/?sc=1&rev=39
Log:
[svn-inject] Installing original source of si

Added:
    si/
    si/branches/
    si/branches/upstream/
    si/branches/upstream/current/
    si/branches/upstream/current/COPYING
    si/branches/upstream/current/FAQ
    si/branches/upstream/current/Makefile
    si/branches/upstream/current/README
    si/branches/upstream/current/buddylist.c
    si/branches/upstream/current/config.mk
    si/branches/upstream/current/contrib/
    si/branches/upstream/current/contrib/buddylist   (with props)
    si/branches/upstream/current/contrib/multitailrc
    si/branches/upstream/current/mit.c
    si/branches/upstream/current/mm.c
    si/branches/upstream/current/si.1
    si/branches/upstream/current/si.c
    si/tags/

Added: si/branches/upstream/current/COPYING
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/COPYING?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/COPYING (added)
+++ si/branches/upstream/current/COPYING Mon May 28 17:37:58 2007
@@ -1,0 +1,345 @@
+!! IMPORTANT !!
+Not the whole si code is under gpl. the code in mit.c is under MIT/X 
+license, because it is copied from ii.
+
+
+		    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.

Added: si/branches/upstream/current/FAQ
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/FAQ?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/FAQ (added)
+++ si/branches/upstream/current/FAQ Mon May 28 17:37:58 2007
@@ -1,0 +1,16 @@
+FAQ
+===
+
+Which commands are supported?
+-----------------------------
+For special commands in si see the manpage. Everything that starts with with
+an slash is sent raw to the server. e.g. /whois stettberger requests
+information about user stettberger
+
+What is this buddylist socket?
+------------------------------
+Through the buddylist unix domain socket in ~irc/${server}/ you can request
+the status of your buddies. You can add somebody to your buddylist by
+requesting his public key (/getkey <username> ) and moving it to
+~/.silc/buddylist. An example code of the buddylist "protocol" you find in
+contrib/buddylist.

Added: si/branches/upstream/current/Makefile
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/Makefile?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/Makefile (added)
+++ si/branches/upstream/current/Makefile Mon May 28 17:37:58 2007
@@ -1,0 +1,51 @@
+CC=gcc
+prefix=/usr/local
+DESTDIR=
+TARGET=si
+
+FILES=si.c mit.c mm.c buddylist.c
+
+include config.mk
+
+all: options si
+
+options:
+	@echo si build options:
+	@echo "LIBS     = ${LIBS}"
+	@echo "INCLUDES = ${INCLUDES}"
+	@echo "CFLAGS   = ${CFLAGS}"
+	@echo "LDFLAGS  = ${LDFLAGS}"
+	@echo "CC       = ${CC}"
+
+si: si.o 
+	${CC} si.o -o si ${LDFLAGS}
+
+si.o: ${FILES}
+	${CC} -c ${CFLAGS} ${TARGET}.c
+clean:
+	rm -f ${TARGET} *~ *.o *core 
+install: all
+	@mkdir -p ${DESTDIR}${DOCDIR}
+	@mkdir -p ${DESTDIR}${BINDIR}
+	@mkdir -p ${DESTDIR}${MAN1DIR}
+
+	@install -d ${DESTDIR}${BINDIR} ${DESTDIR}${MAN1DIR}
+	@install -m 644 COPYING README FAQ buddylist ${DESTDIR}${DOCDIR}
+	@install -m 775 si ${DESTDIR}${BINDIR}
+	@install -m 444 si.1 ${DESTDIR}${MAN1DIR}
+	@echo "installed si"
+
+uninstall: 
+	@rm -f ${DESTDIR}${MAN1DIR}/si.1
+	@rm -rf ${DESTDIR}${DOCDIR}
+	@rm -f ${DESTDIR}${BINDIR}/si
+	@echo "uninstalled si"
+
+dist: clean
+	@mkdir -p si-${VERSION}/contrib
+	@cp -R Makefile README COPYING FAQ config.mk si.c si.1 buddylist.c mit.c mm.c si-${VERSION}
+	@cp -R contrib/buddylist contrib/multitailrc si-${VERSION}/contrib
+	@tar -cf si-${VERSION}.tar si-${VERSION}
+	@gzip si-${VERSION}.tar
+	@rm -rf si-${VERSION}
+	@echo created distribution si-${VERSION}.tar.gz

Added: si/branches/upstream/current/README
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/README?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/README (added)
+++ si/branches/upstream/current/README Mon May 28 17:37:58 2007
@@ -1,0 +1,62 @@
+L I C E N S E   :=
+  
+  Copyright(C) 2006,2007 Christian Dietrich <stettberger at gmx.de>
+   si - silc imporved  
+
+  Some parts of the Code are NOT under GPL. They are licensed unter MIT/X.
+  They could be found in the mit.c file.
+
+  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
+
+F O R E W O R D   :=
+  behind si is an other idea, than behind other chat clients. he has an very
+  simple design, because all the I/O with the user is done through files and
+  fifos. so in its basic variant it isn't so comfortabel, but you can write your
+  own scripts around it or use systems other people had written.
+
+  The SILC protocol is very similar to the IRC protocol, but the main difference
+  is that in SILC all messages are encrypted on the whole way. SILC has also many
+  advantages to irc, like watches or not unique nicknames ( no nickwars )
+
+  si is very untested code, so you will  find bugs. In case you do so,
+  please don't hesitate to fix them. In case you are not able to do so,
+  try to describe it in detail. In detail. And watch out, whether the
+  CVS version already has it fixed.
+
+  besides all the untested code, i think it is usable (for me, at least)
+
+I N S T A L A T I O N  :=
+  first you had to install libsilc (http://silcnet.org)
+
+  cd $sourcedir
+  make
+  make install (as root)
+
+  When your SILC includes/libs are not in /usr/local/silc you had to specify them like 
+  this
+
+  make SILCINCLUDE=/path/to/silc/include SILCLIB=/path/to/silc/lib
+
+I F   I T   D O E S   N O T   W O R K   :=
+
+  please contact me at <stettberger at brokenpipe.de>, but be patient.
+
+L A S T   B U T   N O T   L E A S T   :=
+
+  your contributions are welcome,
+  please help in improving si.
+
+ 
+

Added: si/branches/upstream/current/buddylist.c
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/buddylist.c?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/buddylist.c (added)
+++ si/branches/upstream/current/buddylist.c Mon May 28 17:37:58 2007
@@ -1,0 +1,268 @@
+/*
+ * si - silc improved - minimalistic silc client
+ *
+ * Copyright (C) 2006 Christian Dietrich <stettberger at gmx.de>
+ *
+ * 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
+ *
+ */
+
+/* Buddylist stuff */
+
+#define MAX_CONNS 20
+
+typedef struct BuddyStruct {
+  SilcClientEntry client;
+  struct BuddyStruct *next;
+} *Buddy;
+
+Buddy buddies=NULL;
+int buddy_conns[MAX_CONNS];
+int buddyfd=0;
+
+SILC_TASK_CALLBACK(si_handle_buddyfd_input);
+void send_buddy_list(int fd);
+
+void add_pubkey_callback(SilcClient client, SilcClientConnection conn,
+                         SilcStatus status, SilcDList clients,
+			 void *context);
+
+void 
+refresh_buddylist() 
+{
+  int i;
+  for (i=0; i < MAX_CONNS; i++){
+    if(!buddy_conns[i])
+      continue;
+    write(buddy_conns[i], "update\n", 7);
+  }
+  
+}
+
+void 
+add_buddy(SilcClientEntry client) 
+{
+  Buddy new = calloc(1, sizeof (Buddy)), tmp;
+  NULL_TEST(new);
+  new->client = client;
+  silc_client_ref_client(silc_client->client, silc_client->conn, client);
+  for (tmp = buddies; tmp; tmp = tmp->next)
+    if (tmp->client == client)
+      return;
+  DEBUG("New Buddy on List: %s", client->nickname);
+  if(buddies) {
+    for (tmp = buddies; tmp->next; tmp = tmp->next);
+    tmp->next = new;
+  }
+  else 
+    buddies = new;
+}
+
+void 
+rm_buddy(SilcClientEntry client)
+{
+  Buddy del, tmp;
+  if (buddies && buddies->client == client){
+    buddies = buddies->next;
+    return;
+  }
+  for(del = buddies; del && del->next; del = del->next)
+    if(del->next->client == client){
+      tmp = del->next;
+      del->next = del->next->next;
+      free(tmp);
+      return;
+    }
+}
+
+void 
+add_pubkey(char *pubkey) 
+{
+  SilcBuffer attr=NULL;
+  SilcAttributeObjPk obj;
+  SilcPublicKey pk;
+  /* Request all attributes except PUBKEY */
+  attr = silc_client_attributes_request(SILC_ATTRIBUTE_DEVICE_INFO, 0);
+
+  /* Load the Public Key */
+  if (!silc_pkcs_load_public_key(pubkey, &pk)) { 
+    print_out("", "-!- Couldn't load public key: %s", pubkey);
+    return;
+  }
+  obj.type = "silc-rsa";
+  obj.data = silc_pkcs_public_key_encode(pk, &obj.data_len);
+  
+  attr = silc_attribute_payload_encode(attr,
+					SILC_ATTRIBUTE_USER_PUBLIC_KEY,
+					SILC_ATTRIBUTE_FLAG_VALID,
+					&obj, sizeof(obj));
+  silc_client_get_clients_whois(silc_client->client, silc_client->conn,
+				NULL, NULL, attr, add_pubkey_callback, NULL);
+  /* Add a watch */
+  char *tmp;
+  silc_asprintf(&tmp, "+%s", pubkey);
+  silc_client_command_call(silc_client->client, silc_client->conn, NULL, 
+                           "WATCH", "-add", tmp, NULL);
+  silc_free(tmp);
+}
+
+void 
+add_pubkey_callback(SilcClient client, SilcClientConnection conn,
+                    SilcStatus status, SilcDList clients,
+                    void *context)
+{
+  SilcClientEntry entry;
+  if (!clients) return;
+  silc_dlist_start(clients);
+  while ((entry = (SilcClientEntry)silc_dlist_get(clients))
+         != SILC_LIST_END)  
+      add_buddy(entry);
+}
+
+void 
+update_buddylist() 
+{
+  /* Update the buddylist itself by the Pubkey's in $HOME/.silc/buddylist*/
+  struct dirent *entry;
+  char *path;
+  silc_asprintf(&path, "%s/.silc/buddylist", (char *)getenv("HOME"));
+  create_dirtree(path);
+  DIR *dir = opendir(path);
+  while((entry = readdir(dir))) {
+    if(entry->d_name[0] == '.')
+      continue;
+    char *pubkey;
+    silc_asprintf(&pubkey, "%s/%s", path, entry->d_name);
+    add_pubkey(pubkey);
+    silc_free(pubkey);
+  }
+  closedir(dir);
+  free(path);
+}
+
+void
+init_buddylist() 
+{
+
+  struct sockaddr_un strAddr;
+  socklen_t lenAddr;
+  int yes=1;
+  int i=0;
+
+  while(i < MAX_CONNS){
+    buddy_conns[i] = 0;
+    i++;
+  }
+  
+  update_buddylist();
+  /* Buddyfd */
+  char *path;
+  silc_asprintf(&path,"%s/buddylist", ircdir);
+  unlink(path);
+  if ((buddyfd = socket(PF_UNIX, SOCK_STREAM,0)) == -1) {
+    perror("si: couldn't initalize buddy socket (socket)");
+    return;
+  }
+  if (setsockopt(buddyfd, SOL_SOCKET, SO_REUSEADDR,
+		 (char *) &yes, sizeof(yes)) < 0) {
+    perror("si: couldn't initalize buddy socket (setsockopt)");
+    return;
+  }
+  strAddr.sun_family = AF_UNIX; /* Unix Domain */
+  strcpy(strAddr.sun_path, path);
+  lenAddr = sizeof(strAddr.sun_family)+strlen(strAddr.sun_path);
+  silc_free(path);
+
+  if (bind(buddyfd, (struct sockaddr*)&strAddr, lenAddr) < 0) {
+    perror("si: couldn't initalize buddy socket (bind)");
+    return;
+  }
+  if (listen(buddyfd, MAX_CONNS) != 0){
+    perror("si: couldn't initalize buddy socket (listen)");
+    return;
+  }
+  silc_schedule_task_add_fd(silc_client->client->schedule, buddyfd,
+			 si_handle_buddyfd_input, &strAddr);
+}
+
+SILC_TASK_CALLBACK(si_handle_buddyfd_input) 
+{
+  int conn=0;
+  socklen_t lenAddr;
+  int i;
+  struct sockaddr_un *addr = context;
+  lenAddr = sizeof(addr->sun_family) + strlen(addr->sun_path);
+  if((conn = accept(fd, (struct sockaddr *) addr, &lenAddr))<0) {
+    perror("si: couldn't accept connection on buddylist");
+    return;
+  }
+  for(i = 0; i < MAX_CONNS; i++)
+    if(! buddy_conns[i]){
+      buddy_conns[i] = conn;
+      break;
+    }
+  DEBUG("New Connection on Buddylist");
+}
+
+void 
+si_handle_buddy_conn_input(int fd) 
+{
+  int pos = 0, len = 1;
+  char buf[1], *data = emalloc(len);
+  int count=0;
+  data[0]=0;
+  while(buf[0] != '\n' && (count = read(fd, buf, 1)) > 0){
+    len += count;
+    data = realloc(data, len);
+    NULL_TEST(data);
+    data = strcat(data, buf);
+  }
+  if(count <= 0) {
+    DEBUG("Closed connection on Buddylist");
+    pos=0;
+    while(pos < MAX_CONNS) {
+      if(buddy_conns[pos] == fd)
+	buddy_conns[pos] = 0;
+      pos++;
+    }
+    close(fd);
+    return;
+  }
+  char *p = strchr(data, '\n');
+  p[0] = 0;
+  /* Proc data */
+  if(! strncmp("getbuddylist", data, 12)) 
+    send_buddy_list(fd);
+
+  silc_free(data);
+}
+
+void 
+send_buddy_list(int fd) 
+{
+  Buddy tmp;
+  char *umode, *line;
+  for(tmp = buddies; tmp; tmp = tmp->next) {
+    umode = silc_client_umode(tmp->client->mode);
+    silc_asprintf(&line, "%s,%s\n", umode, tmp->client->nickname);
+    write(fd, line, strlen(line));
+    silc_free(line);
+    silc_free(umode);
+    fsync(fd);
+  }
+  write(fd, "END,nouser\n", 11);
+  fsync(fd);
+}

Added: si/branches/upstream/current/config.mk
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/config.mk?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/config.mk (added)
+++ si/branches/upstream/current/config.mk Mon May 28 17:37:58 2007
@@ -1,0 +1,22 @@
+# customize to fit your system
+
+# paths
+PREFIX      = /usr/local
+BINDIR      = ${PREFIX}/bin
+MANDIR      = ${PREFIX}/share/man
+MAN1DIR     = ${MANDIR}/man1
+DOCDIR      = ${PREFIX}/share/doc/si
+
+# # includes and libs
+INCLUDES    = `pkg-config --cflags silc silcclient` 
+LIBS        = `pkg-config --libs silc silcclient`
+
+VERSION=0.3
+
+## change DESTDIR to install to a different root
+DESTDIR =
+
+# # compiler
+CC          = gcc
+CFLAGS      = -ggdb -O0 -W ${INCLUDES} -DVERSION=\"${VERSION}\" -DSILC_DIST_SKR -DSILC_DIST_TMA 
+LDFLAGS     = ${LIBS}

Added: si/branches/upstream/current/contrib/buddylist
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/contrib/buddylist?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/contrib/buddylist (added)
+++ si/branches/upstream/current/contrib/buddylist Mon May 28 17:37:58 2007
@@ -1,0 +1,105 @@
+#!/usr/bin/python
+
+import socket, select, os, sys, re, time
+import curses
+
+
+class BuddyList:
+    def __init__(self, server, prefix="%s/irc"%os.environ['HOME'], buffer=1024):
+        self.server=os.path.join(prefix,server)
+        self.server=os.path.join(self.server, "buddylist")
+        self.socket=socket.socket(socket.AF_UNIX, socket.SOCK_STREAM,0)
+        self.buffer=buffer
+        try:
+            self.socket.connect(self.server)
+        except:
+            self.socket=None
+    def has_data(self):
+        try:
+            (iwtd, owtd, ewtd)=select.select([self.socket],[],[],0.05)
+        except:
+            return False
+        if len(iwtd)==0:
+            return False
+        return True
+    def get_buddylist(self):
+        self.socket.send("getbuddylist\n")
+        text=self.socket.recv(self.buffer)
+        ret=[]
+        for i in text.split('\n'):
+            (status, nickname)=i.split(",",2)
+            if(status=="END"):
+                return ret
+            ret.append([status, nickname])
+        return ret
+    def read(self):
+        return self.socket.recv(self.buffer).replace("\n", "")
+
+class DeMultiplexer:
+    def __init__(self, prefix="%s/irc"%os.environ['HOME']):
+        self.servers=[]
+        self.scr=None
+        self.buddylist=[]
+        for i in os.walk(prefix):
+            if  "buddylist" in i[2]:
+                server=BuddyList(i[0].replace(prefix, "")[1:])
+                if server.socket==None:
+                    continue
+                self.servers.append(server)
+    def init_curses(self):
+        self.scr = curses.initscr()
+        curses.start_color()
+        curses.noecho()
+        curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK)
+        curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
+        curses.init_pair(3, curses.COLOR_BLUE, curses.COLOR_BLACK)
+        self.scr.attron(curses.A_BOLD)
+    def sort_buddylist(self):
+        online=[]
+        away=[]
+        gone=[]
+        detach=[]
+        for i in self.buddylist:
+            if "D" in i[0]: detach.append(i)
+            elif "G" in i[0]: gone.append(i)
+            elif "I" in i[0]: away.append(i)
+            else: online.append(i)
+        self.buddylist=[]
+        for i in online: self.buddylist.append(i)
+        for i in away: self.buddylist.append(i)
+        for i in gone: self.buddylist.append(i)
+        for i in detach: self.buddylist.append(i)
+    def refresh(self):
+        self.buddylist=[]
+        for i in self.servers:
+            for x in i.get_buddylist():
+                self.buddylist.append(x)
+        self.scr.clear()
+        self.sort_buddylist()
+        for i in self.buddylist:
+            if "D" in i[0]:
+                self.scr.addstr("[%s] %s\n"%(i[0], i[1]), curses.color_pair(3))
+            elif "G" in i[0]:
+                self.scr.addstr("[%s] %s\n"%(i[0], i[1]), curses.color_pair(3) | curses.A_BOLD)
+            elif "I" in i[0]:
+                self.scr.addstr("[%s] %s\n"%(i[0], i[1]), curses.color_pair(2) | curses.A_BOLD)
+            else:
+                self.scr.addstr("[%s] %s\n"%(i[0], i[1]), curses.color_pair(1) | curses.A_BOLD)
+        self.scr.refresh()
+    def run(self):
+        self.init_curses()
+        self.refresh()
+        try:
+            while True:
+                for i in self.servers:
+                    if i.has_data():
+                        if i.read() == "update":
+                            self.refresh()
+                time.sleep(1)
+        except:
+            curses.endwin()
+                            
+fd=DeMultiplexer()
+fd.run()
+
+sys.exit(1)

Propchange: si/branches/upstream/current/contrib/buddylist
------------------------------------------------------------------------------
    svn:executable = 

Added: si/branches/upstream/current/contrib/multitailrc
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/contrib/multitailrc?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/contrib/multitailrc (added)
+++ si/branches/upstream/current/contrib/multitailrc Mon May 28 17:37:58 2007
@@ -1,0 +1,31 @@
+#allow_8bit:yes
+
+colorscheme:irc
+# messages
+cs_re_s:magenta,,bold:^..:.. [<].*(stettberger)[>].*$
+cs_re_s:yellow,,bold:^..:.. <([^<>]+)>.+$
+cs_re_s:green:^..:.. [<].*stettberger[>](.*)$
+cs_re_s:yellow:^..:.. .*(stettberger)[,:].*$
+cs_re_s:cyan:^(..:..).*$
+cs_re_s:yellow:^..:.. (\[.*\]).*$
+cs_re:yellow:(http:\/\/[a-zA-Z&\?.0-9+\=+-_~#/]+)
+cs_re_s:magenta:^..:.. \[.*\] <([^<>]*)>.*$
+cs_re_s:red:^..:.. \[.*\] >([^<>]*)<.*$
+cs_re_s:red:^..:.. >([^<>]*)<.*$
+
+# Watches Errors and other status messages
+cs_re_s:blue:^..:...*(-!-)
+cs_re_s:green:^..:...*(-\?!-)
+cs_re_s:red:^..:...*-!- (Error [^\s]+:)
+cs_re_s:yellow:^..:...*-!- (Watch:)
+
+# Status lines
+cs_re_s:cyan,,bold:^..:.. -!- ([^ \(\[]*)
+cs_re_s:cyan:^..:.. -!- [^ \(\[]*(.*) has
+cs_re_s:green:^..:.. -!- [^ \(\[]*.* (has) quit (.*)
+cs_re_s:red:^..:.. -!- [^ \(\[]*.* (quit)
+cs_re_s:green:^..:.. -!- [^ \(\[]*(.*)
+cs_re_s:,,bold:_([^ ]*)_
+
+titlebar:%m %u@%h %f (%t) [%l]
+tail:/usr/bin/turbotail

Added: si/branches/upstream/current/mit.c
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/mit.c?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/mit.c (added)
+++ si/branches/upstream/current/mit.c Mon May 28 17:37:58 2007
@@ -1,0 +1,265 @@
+/* MIT/X Consortium License
+
+* (C)opyright MMV Anselm R. Garbe <garbeam at wmii.de>
+* (C)opyright MMV Nico Golde <nico at ngolde dot de>
+
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+
+
+static char *
+lower(char *s) 
+{
+	char *p;
+	for(p = s; p && *p; p++) *p = tolower(*p);
+	return s;
+}
+
+/* creates directories top-down, if necessary */
+static void 
+create_dirtree(const char *dir) 
+{
+	char tmp[256];
+	char *p;
+	size_t len;
+
+	snprintf(tmp, sizeof(tmp),"%s",dir);
+	len = strlen(tmp);
+	if(tmp[len - 1] == '/')
+		tmp[len - 1] = 0;
+	for(p = tmp + 1; *p; p++)
+		if(*p == '/') {
+			*p = 0;
+			mkdir(tmp, S_IRWXU);
+			*p = '/';
+		}
+	mkdir(tmp, S_IRWXU);
+}
+
+static int 
+get_filepath(char *filepath, size_t len, char *channel, char *file)
+{
+	if(strlen(channel)!=0) {
+		if(!snprintf(filepath, len, "%s/%s", ircdir, lower(channel)))
+			return 0;
+		create_dirtree(filepath);
+		return snprintf(filepath, len, "%s/%s/%s", ircdir,lower(channel), file);
+	}
+	return snprintf(filepath, len, "%s/%s", ircdir, file);
+}
+
+static void 
+create_filepath(char *filepath, size_t len, char *channel, char *suffix)
+{
+	if(!get_filepath(filepath, len, channel, suffix)) {
+		fprintf(stderr, "%s", "ii: path to irc directory too long\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static int 
+open_channel(char *name)
+{
+	static char infile[256];
+	create_filepath(infile, sizeof(infile), name, "in");
+	if(access(infile, F_OK) == -1)
+		mkfifo(infile, S_IRWXU);
+	return open(infile, O_RDONLY | O_NONBLOCK, 0);
+}
+
+static int
+read_line(int fd, size_t res_len, char *buf)
+{
+	size_t i = 0;
+	char c;
+	do {
+	  if(read(fd, &c, sizeof(char)) != sizeof(char))
+	    return -1;
+	  buf[i++] = c;
+	}
+	while(c != '\n' && i < res_len);
+	buf[i - 1] = 0;			/* eliminates '\n' */
+	return 0;
+}
+
+static void 
+rm_channel(Channel *c)
+{
+  Channel *p;
+  if(channels == c) {
+    c->silc->context = NULL;
+    channels = channels->next;
+  } else
+    for(p = channels; p; p = p->next)
+      if(p->next == c) {
+	p->silc->context = NULL;
+	p->next = c->next;
+      }
+  free(c);
+}
+
+static void 
+handle_channels_input(Channel *c)
+{
+  static char buf[PIPE_BUF];
+
+  if (read_line(c->fd, PIPE_BUF, buf) == -1) {
+    int fd = open_channel(c->silc->channel_name);
+    if(fd != -1)
+      c->fd = fd;
+    else
+      rm_channel(c);
+    return;
+  }
+  proc_channels_input(c, buf);
+}
+
+static void 
+add_channel(SilcChannelEntry channel)
+{
+  Channel *c;
+  int fd;
+
+  if (channel->context)
+    return; /* already handled */
+
+  fd = open_channel(channel->channel_name);
+  if(fd == -1) {
+    perror("si: cannot create in channel");
+    return;
+  }
+  c = calloc(1, sizeof(*c));
+  NULL_TEST_ARG(c, exit(1));
+  if(!channels)
+    channels = c;
+  else {
+    c->next = channels;
+    channels = c;
+  }
+  c->fd = fd;
+  c->silc = channel;
+  c->silc->context = c;
+}
+
+void 
+rm_query(Query *peer) 
+{
+  Query *q;
+  if (peer == queries) {
+    peer->silc->context = NULL;
+    queries = queries->next;
+  }
+  else
+    for (q = queries; q; q = q->next)
+      if (SILC_ID_CLIENT_COMPARE(&peer->silc->id, 
+                                 &q->next->silc->id)) {
+	q->silc->context = NULL;
+	q->next = peer->next;
+      }
+  free(peer);
+}
+
+static void handle_query_input(Query *peer)
+{
+  static char buf[PIPE_BUF];
+  char *path;
+
+  if(read_line(peer->fd, PIPE_BUF, buf) == -1) {
+    path=malloc(strlen(peer->silc->nickname)+8);
+    NULL_TEST(path);
+    int fd = open_channel(path);
+    if(fd != -1)
+      peer->fd = fd;
+    else
+      rm_query(peer);
+    return;
+  }
+  proc_queries_input(peer, buf);
+}
+
+void 
+add_query(SilcClientEntry peer) 
+{
+  Query *q;
+  int fd;
+  char *path;
+
+  if (peer->context)
+    return; /* Already handled */
+
+  
+  silc_asprintf(&path, "query/%s", peer->nickname);
+  fd = open_channel(path);
+  if(!fd){
+    perror("si: Couldn't create Query");
+    return;
+  }
+  q = calloc(1, sizeof(Query));
+  NULL_TEST_ARG(q, exit(1));
+  /* Write to the query */
+  print_out(path, "-!- You opened the query");
+  if (!queries) {
+    queries = q;
+  }
+  else {
+    q->next = queries;
+    queries = q;
+  }
+  q->silc = peer;
+  q->fd = fd;
+  q->silc->context = q;
+
+  silc_client_ref_client(silc_client->client, silc_client->conn, peer);
+}
+
+void 
+add_transfer(int num, SilcUInt32 id, SilcClientEntry sender, int type) 
+{
+  Transfer *t, *tmp;
+  t = calloc(1, sizeof(Transfer));
+  NULL_TEST(t);
+  if(!transfers)
+    transfers = t;
+  else{
+    tmp = transfers;
+    while(tmp->next)
+      tmp = tmp->next;
+    tmp->next = t;
+  }
+  t->number = num;
+  t->id = id;
+  t->silc = sender;
+  t->type = type;
+  t->status = FILE_STATUS_WAIT;
+}
+
+void 
+rm_transfer(Transfer *t) 
+{
+  Transfer *tmp;
+  if (t == transfers) {
+    transfers = transfers->next;
+  }
+  else
+    for (tmp = transfers; tmp; tmp = tmp->next)
+      if(tmp->next->id == t->id)
+	tmp->next = t->next;
+  free(t);
+}

Added: si/branches/upstream/current/mm.c
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/mm.c?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/mm.c (added)
+++ si/branches/upstream/current/mm.c Mon May 28 17:37:58 2007
@@ -1,0 +1,365 @@
+/*
+
+  mm.c
+
+  Author: Pekka Riikonen <priikone at silcnet.org>
+
+  Copyright (C) 2006 Pekka Riikonen
+  Copyright (C) 2007 Stefan Siegl <stesie at brokenpipe.de>
+
+  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; version 2 of the License.
+
+  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.
+
+*/
+
+/* Multimedia routines */
+
+SILC_TASK_CALLBACK(si_handle_data_input);
+
+/* MIME fragment assembler */
+SilcMimeAssembler mimeass = NULL;
+
+/* Process incoming MIME message */
+
+static void
+si_process_mime(SilcClient client, SilcClientConnection conn,
+		SilcClientEntry sender, SilcChannelEntry channel,
+		SilcMessagePayload payload, SilcChannelPrivateKey key,
+		SilcMessageFlags flags, SilcMime mime, bool recursive)
+{
+  const char *type;
+  const unsigned char *data;
+  SilcUInt32 data_len;
+  SIMime simime = NULL;
+  Channel *c;
+  Query *q;
+  static char outfile[1024], tmp[1024];
+  int ret;
+
+  if (!mime)
+    return;
+
+  /* Check for fragmented MIME message */
+  if (silc_mime_is_partial(mime)) {
+    if (!mimeass)
+      mimeass = silc_mime_assembler_alloc();
+
+    /* Defragment */
+    mime = silc_mime_assemble(mimeass, mime);
+    if (!mime)
+      /* More fragments to come */
+      return;
+
+    /* Process the complete message */
+    si_process_mime(client, conn, sender, channel, payload, key,
+		    flags, mime, FALSE);
+    return;
+  }
+
+  /* Check for multipart message */
+  if (silc_mime_is_multipart(mime)) {
+    SilcMime p;
+    const char *mtype;
+    int is_alternative;
+    SilcDList parts = silc_mime_get_multiparts(mime, &mtype);
+
+    /* Only "mixed" type supported */
+    is_alternative = strcmp(mtype, "alternative") == 0;
+    if (!is_alternative && strcmp(mtype, "mixed"))
+      goto out;
+
+    silc_dlist_start(parts);
+    while ((p = silc_dlist_get(parts)) != SILC_LIST_END) {
+      /* Recursively process parts */
+      si_process_mime(client, conn, sender, channel, payload,
+		      key, flags, p, TRUE);
+      
+      /* Content-type set to multipart/alternative,
+       * handle the first alternative only */
+      if(is_alternative)
+        break;
+    }
+    goto out;
+  }
+
+  /* Get content type and MIME data */
+  type = silc_mime_get_field(mime, "Content-Type");
+  if (!type)
+    goto out;
+  data = silc_mime_get_data(mime, &data_len);
+  if (!data)
+    goto out;
+
+  /* Process according to content type */
+
+  /* Plain text */
+  if (strstr(type, "text/plain")) {
+    /* Default is UTF-8, don't check for other charsets */
+    if (!strstr(type, "utf-8"))
+      goto out;
+
+    if (channel)
+      silc_channel_message(client, conn, sender, channel, payload, key,
+			   SILC_MESSAGE_FLAG_UTF8, data, data_len);
+    else
+      silc_private_message(client, conn, sender, payload,
+			   SILC_MESSAGE_FLAG_UTF8, data, data_len);
+    goto out;
+  }
+
+  /* Process supported types */
+
+  if (channel) {
+    c = channel->context;
+
+    /* Check if we support this MIME type */
+    for (simime = c->mimes; simime; simime = simime->next) {
+      const char *mtype = silc_mime_get_field(simime->mime, "Content-Type");
+      if (!strcmp(mtype, type))
+	break;
+    }
+    if (!simime)
+      goto out; /* Unsupported MIME type */
+
+    if (simime->out_fd < 0) {
+      memset(tmp, 0, sizeof(tmp));
+      snprintf(tmp, sizeof(tmp) - 1, "out-%s", type);
+      if (strrchr(tmp, '/'))
+	*strrchr(tmp, '/') = '-';
+      create_filepath(outfile, sizeof(outfile), channel->channel_name, tmp);
+    }
+
+  } else {
+    q = sender->context;
+
+    /* Check if we support this MIME type */
+    for (simime = q->mimes; simime; simime = simime->next) {
+      const char *mtype = silc_mime_get_field(simime->mime, "Content-Type");
+      if (!strcmp(mtype, type))
+	break;
+    }
+    if (!simime)
+      goto out; /* Unsupported MIME type */
+
+    if (simime->out_fd < 0) {
+      memset(tmp, 0, sizeof(tmp));
+      snprintf(tmp, sizeof(tmp) - 1, "%s/out-%s", sender->nickname, type);
+      if (strrchr(tmp, '/'))
+	*strrchr(tmp, '/') = '-';
+      create_filepath(outfile, sizeof(outfile), "query", tmp);
+    }
+  }
+
+  if (simime->out_fd < 0) {
+    int flags = O_WRONLY;
+
+    /* Open FIFO for writing */
+    if (access(outfile, F_OK) == -1)
+      mkfifo(outfile, S_IRWXU);
+
+    if (simime->buffer == FALSE)
+      flags |= O_NONBLOCK;
+    simime->out_fd = open(outfile, flags, 0);
+    if (simime->out_fd < 0)
+      goto out;
+  }
+
+  /* Write to FIFO */
+  while (data_len > 0) {
+    ret = write(simime->out_fd, data, data_len);
+    if (ret <= 0) {
+      if (errno == EPIPE) {
+	close(simime->out_fd);
+	simime->out_fd = -1;
+      }
+      break;
+    }
+    data += ret;
+    data_len -= ret;
+  }
+
+ out:
+  if (!recursive)
+    silc_mime_free(mime);
+}
+
+/* Creates a data input FIFO */
+
+static int si_open_data_fifo(char *path, char *suffix, void *context)
+{
+  char infile[1024], tmp[32];
+  int fd;
+
+  memset(infile, 0, sizeof(infile));
+  memset(tmp, 0, sizeof(tmp));
+
+  snprintf(tmp, sizeof(tmp) - 1, "in-%s", suffix);
+  if (strrchr(tmp, '/'))
+    *strrchr(tmp, '/') = '-';
+  create_filepath(infile, sizeof(infile), path, tmp);
+
+  /* Open FIFO */
+  if (access(infile, F_OK) == -1)
+    mkfifo(infile, S_IRWXU);
+  fd = open(infile, O_RDONLY | O_NONBLOCK, 0);
+
+  /* Add to scheduler */
+  if (fd != -1)
+    silc_schedule_task_add_fd(silc_client->client->schedule, fd,
+			   si_handle_data_input, context);
+
+  return fd;
+}
+
+/* Task callback to handle data input from FIFO */
+
+SILC_TASK_CALLBACK(si_handle_data_input)
+{
+  SIMime simime = context;
+  Channel *c;
+  Query *q;
+  unsigned char buf[0xffff - 512];
+  unsigned char *data;
+  SilcUInt32 data_len;
+  int ret;
+
+  ret = read(fd, buf, sizeof(buf));
+  if (ret <= 0) {
+    if (errno == EPIPE) {
+      /* Writer went away, close and reopen FIFO */
+      close(fd);
+      silc_schedule_unset_listen_fd(silc_client->client->schedule, fd);
+      silc_schedule_task_del_by_fd(silc_client->client->schedule, fd);
+      if (simime->type == CHANNEL) {
+	c = simime->context;
+	si_open_data_fifo(c->silc->channel_name,
+			  (char *)silc_mime_get_field(simime->mime,
+						      "Content-Type"),
+			  context);
+      } else {
+	q = simime->context;
+	snprintf((char *)buf, sizeof(buf) - 1, "query/%s", q->silc->nickname);
+	si_open_data_fifo((char *)buf, (char *)silc_mime_get_field(simime->mime,
+							   "Content-Type"),
+			  context);
+
+      }
+    }
+    return;
+  }
+
+  /* Encode the data */
+  silc_mime_add_data(simime->mime, buf, ret);
+  data = silc_mime_encode(simime->mime, &data_len);
+  if (!data)
+    return;
+
+  /* Send the MIME data */
+  if (simime->type == CHANNEL) {
+    c = simime->context;
+    silc_client_send_channel_message(silc_client->client,
+				     silc_client->conn, c->silc,
+                                     NULL, SILC_MESSAGE_FLAG_DATA,
+				     silc_client->hash, data, data_len);
+  } else {
+    q = simime->context;
+    silc_client_send_private_message(silc_client->client,
+				     silc_client->conn, q->silc,
+				     SILC_MESSAGE_FLAG_DATA, 
+                                     silc_client->hash,
+                                     data, data_len);
+  }
+
+  silc_free(data);
+}
+
+/* Open data FIFO for input */
+
+static void si_open_mime(void *context, ContextType type, char *mimetype,
+			 bool buffer)
+{
+  SIMime simime, mimes;
+  Channel *c;
+  Query *q;
+  int fd;
+  char path[1024];
+
+  memset(path, 0, sizeof(path));
+  if (type == CHANNEL) {
+    c = context;
+    mimes = c->mimes;
+    snprintf(path, sizeof(path) - 1, "%s", c->silc->channel_name);
+  } else {
+    q = context;
+    mimes = q->mimes;
+    snprintf(path, sizeof(path) - 1, "query/%s", q->silc->nickname);
+  }
+
+  DEBUG("Input: MIME %s buffered=%s", mimetype, buffer ? "yes" : "no");
+
+  for (simime = mimes; simime; simime = simime->next) {
+    const char *mtype = silc_mime_get_field(simime->mime, "Content-Type");
+
+    if (!strcmp(mtype, mimetype)) {
+      if (simime->buffer != buffer && simime->out_fd != -1) {
+	close(simime->out_fd);
+	simime->out_fd = 1;
+      }
+      simime->buffer = buffer;
+
+      /* Already handled */
+      return;
+    }
+  }
+
+  simime = silc_calloc(1, sizeof(*simime));
+  if (!simime) {
+    perror(("si: cannot open FIFO, out of memory"));
+    return;
+  }
+  simime->out_fd = -1;
+  simime->buffer = buffer;
+  simime->type = type;
+  simime->context = context;
+  simime->mime = silc_mime_alloc();
+  if (!simime->mime) {
+    perror(("si: cannot open FIFO, out of memory"));
+    silc_free(simime);
+    return;
+  }
+  silc_mime_add_field(simime->mime, "MIME-Version", "1.0");
+  silc_mime_add_field(simime->mime, "Content-Type", mimetype);
+  silc_mime_add_field(simime->mime, "Content-Transfer-Encoding", "binary");
+
+  fd = si_open_data_fifo(path, mimetype, simime);
+  if (fd < 0) {
+    perror(("si: cannot open FIFO"));
+    silc_mime_free(simime->mime);
+    silc_free(simime);
+    return;
+  }
+
+  if (type == CHANNEL) {
+    c = context;
+    if (!c->mimes)
+      c->mimes = simime;
+    else {
+      simime->next = c->mimes;
+      c->mimes = simime;
+    }
+  } else {
+    q = context;
+    if (!q->mimes)
+      q->mimes = simime;
+    else {
+      simime->next = q->mimes;
+      q->mimes = simime;
+    }
+  }
+}

Added: si/branches/upstream/current/si.1
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/si.1?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/si.1 (added)
+++ si/branches/upstream/current/si.1 Mon May 28 17:37:58 2007
@@ -1,0 +1,141 @@
+.de FN
+\fI\|\\$1\|\fP\\$2
+..
+.TH SI 1 "May 26, 2007"
+.SH NAME
+si \- silc improved
+.SH SYNOPSIS
+.B si
+.RB [ \-s
+.IR servername ]
+.RB [ \-p
+.IR port ]
+.RB [ \-k
+.IR password ]
+.RB [ \-i
+.IR prefix ]
+.RB [ \-n
+.IR nickname ]
+.RB [ \-x
+.IR filename ]
+.RB [ \-v ]
+.RB [ \-F ]
+.RB [ \-d ]
+
+.SH DESCRIPTION
+.B si
+is a minimalistic FIFO and filesystem based SILC client.
+It creates an irc directory tree with server, channel and
+nick name directories.
+In every directory a FIFO file (in) and and normal file (out)
+is placed. This will be for example ~/irc/sauna.silcnet.org/.
+The in file is used to communicate with the servers and the out
+files includes the server messages. For every channel and every nick
+name there will be new in and out files.
+The basic idea of this is to be able to communicate with an IRC
+server with basic command line tools.
+For example if you will join a channel just do echo "/join #channel" > in
+and si creates a new channel directory with in and out file.
+.SH OPTIONS
+.TP
+.BI \-s " servername"
+lets you override the default servername (sauna.silcnet.org)
+.TP
+.BI \-p " port"
+lets you override the default port (706)
+.TP
+.BI \-i " prefix"
+lets you override the default irc path (~/irc)
+.TP
+.BI \-n " nickname"
+lets you override the default nick ($USER)
+.TP
+.BI \-x " file"
+lets you provide a init script, which is executed upon successful connection.
+Use a plain file listing one silc command, including the slash, per line.
+.TP
+.BI \-v
+display version number and exit.
+.TP
+.BI \-F
+fork to background and exit.
+.TP
+.BI \-d
+enable debugging output.
+
+.SH DIRECTORIES
+.TP
+.FN ~/irc
+In this directory the silc tree will be created. In this directory you
+will find a directory for your server (default: sauna.silcnet.org) in
+which the FIFO and the output file will be stored.
+If you join a channel a new directory with the name of the channel
+will be created in the ~/irc/$servername/ directory.
+
+.SH COMMANDS
+.TP
+.FN /join " channel"
+join a channel 
+.TP
+.FN /query " nickname"
+start a private conversation with the user
+.TP
+.FN /leave " channel"
+leave a channel
+.TP
+.FN /chaninfo " <topic|mode>"
+print inforation about a channel
+.TP
+.FN /update
+refresh the buddylist
+.TP
+.FN /me " action"
+send an action message
+.TP
+.FN /file 
+.RS
+.TP 
+.FN list 
+list all filetransfers
+.TP
+.FN accept " <number>"
+accept a filetransfer
+.TP
+.FN send " <nick> <path> [-no-listener]"
+send an filetransfer a file. With -no-listener the other side has to bind
+.TP
+.FN close " <number>"
+close a filetransfer
+.RE
+.TP
+.FN /names
+print users on a channel
+.TP
+.FN /msg " <user> <message>
+send private message to user
+.TP
+.FN /set
+.RS
+.TP
+.FN signed " <on|off>
+send signed messages
+.TP
+.FN signal_detach " <on|off>"
+detach the session on an signal (e.g. SIGTERM), so i can be resumed with next connect
+.TP
+.FN auto_away " <on|off>"
+set usermode to away after a few minutes of inactiviy
+.RE
+.TP
+.FN /mime " <mime-type> [-buffer]>"
+open an fifo for sending mime messages
+.TP
+Everything which is not a command, i.e. not starting with a slash, will simply be posted into the channel or to the server.
+.TP
+.FH out file usage
+Write wrappers, pagers or use your tools of choice to display the out file contents (loco, multitail, etc.). 
+.SH AUTHORS
+si was written by Christian Dietrich <stettberger at brokenpipe.de>.
+.SH SEE ALSO
+.BR echo (1),
+.BR tail (1),

Added: si/branches/upstream/current/si.c
URL: http://svn.debian.org/wsvn/pkg-silc/si/branches/upstream/current/si.c?rev=39&op=file
==============================================================================
--- si/branches/upstream/current/si.c (added)
+++ si/branches/upstream/current/si.c Mon May 28 17:37:58 2007
@@ -1,0 +1,2218 @@
+/*
+ * si - silc improved - minimalistic silc client
+ *
+ * Copyright (C) 2006 Christian Dietrich <stettberger at gmx.de>
+ * Copyright (C) 2006 Stefan Siegl <stesie at brokenpipe.de>
+ *
+ * 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
+ *
+ */
+
+#include <silc.h>	/* Mandatory include for SILC applications */
+#include <silcclient.h>		/* SILC Client Library API */
+#include <silcmime.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/* {{{  Structs, Globals Declarations */
+
+#define NULL_TEST(a) if(!(a)){perror("si: Couldn't allocate memory"); return;}
+#define NULL_TEST_ARG(a,b) if(!(a)){perror("si: Couldn't allocate memory"); return (b);}
+
+/* This is context for our client */
+enum FileTransferStatus {
+  FILE_STATUS_WAIT,
+  FILE_STATUS_RUN,
+  FILE_STATUS_COMP,
+  FILE_STATUS_ERR
+};
+
+enum FileTransferType {
+  FILE_TYPE_IN,
+  FILE_TYPE_OUT
+};
+
+enum PublicKeyStatus {
+  KEY_UNKOWN,
+  KEY_INVALID,
+  KEY_TRUSTED
+};
+
+enum RemoteSide {
+  SERVER,CLIENT
+};
+
+typedef enum {
+  CHANNEL,
+  QUERY
+} ContextType;
+
+typedef struct {
+  SilcClient client;		/* The actual SILC Client */
+  SilcClientConnection conn;	/* Connection to the server */
+  /* Config */
+  int sign:1;
+  int detach_on_signal:1;
+  int auto_away:1;
+  SilcPublicKey pubkey;
+  SilcPrivateKey privkey;
+  SilcHash hash;
+} *Silc;
+
+/* Mime context */
+typedef struct SIMimeStruct {
+  int out_fd;
+  int buffer;
+  SilcMime mime;
+  ContextType type;
+  void *context;
+  struct SIMimeStruct *next;
+} *SIMime;
+
+typedef struct Channel Channel;
+struct Channel {
+  int fd;
+  SilcChannelEntry silc;
+  SIMime mimes;
+  Channel *next;
+};
+
+typedef struct Query Query;
+struct Query {
+  int fd;
+  SilcClientEntry silc;
+  SIMime mimes;
+  Query *next;
+};
+
+typedef struct Transfer Transfer;
+struct Transfer {
+  int number;
+  int type;
+  int status;
+  long starttime;
+  float percent;
+
+  SilcUInt32 id;
+  SilcClientEntry silc;
+
+  Transfer *next;
+};
+
+char *prefix = "";
+char *username = NULL;
+SilcClientEntry resolve_name = NULL;
+char *realname = NULL;
+char *host = "sauna.silcnet.org";
+char *init_script = NULL;
+int  port = 706;
+char *ircdir = NULL;
+Channel *channels = NULL;
+Query *queries = NULL;
+Transfer *transfers = NULL;
+int debug = 0;
+int connected = 0;
+SilcClientOperations ops;
+Silc silc_client;
+time_t last_input;
+int transfer_count = 1;
+
+
+void DEBUG(char *fmt, ...);
+int LocalToUtf8 (char *from, char **to);
+int Utf8ToLocal (char *from, char **to);
+void file_transfer(SilcClient client,
+		   SilcClientConnection conn,
+		   SilcClientMonitorStatus status,
+		   SilcClientFileError error,
+		   SilcUInt64 offset,
+		   SilcUInt64 filesize,
+		   SilcClientEntry client_entry,
+		   SilcUInt32 session_id,
+		   const char *filepath,
+		   void *context);
+char channel_user_mode(SilcClientEntry client, SilcChannelEntry channel);
+void proc_channels_input(Channel *c, char *buf);
+void proc_queries_input (Query *peer, char *buf );
+static void print_out(char *channel, char *buf, ...);
+char *silc_client_umode(SilcUInt32 mode);
+void run_once();
+SilcClientEntry silc_client_get_client_entry(const char *nick);
+void silc_connection_cb(SilcClient client,
+                        SilcClientConnection conn,
+                        SilcClientConnectionStatus status,
+                        SilcStatus error,
+                        const char *message,
+                        void *context);
+static void
+silc_channel_message(SilcClient client, SilcClientConnection conn,
+		     SilcClientEntry sender, SilcChannelEntry channel,
+		     SilcMessagePayload payload,
+		     SilcChannelPrivateKey key,
+		     SilcMessageFlags flags, const unsigned char *content,
+		     SilcUInt32 message_len);
+static void
+silc_private_message(SilcClient client, SilcClientConnection conn,
+		     SilcClientEntry sender, SilcMessagePayload payload,
+		     SilcMessageFlags flags,
+		     const unsigned char *msg,
+		     SilcUInt32 message_len);
+void *emalloc(size_t size);
+
+/* All Copied Functions from ii */
+#include "mit.c"
+#include "mm.c"
+#include "buddylist.c"
+
+/* }}} */
+/* {{{ Usage & Version*/
+static void usage()
+{
+	fprintf(stderr, "%s",
+			"si - silc improved - " VERSION "\n"
+			"(C)opyright 2006 Christian Dietrich\n"
+			"usage: si [-hvdF] [-i <silc dir>] [-s <host>] [-p <port>]\n"
+			"          [-n <nick>] [-f <fullname>] [-x <init-script>]\n");
+	exit(EXIT_SUCCESS);
+}
+static void version() {
+  fprintf(stderr, "%s","si - silc improved - " VERSION "\n");
+  exit(EXIT_SUCCESS);
+}
+/* }}} */
+/* {{{ unimportant (Debug, stubs) */
+
+void DEBUG(char *fmt, ...)
+{
+  if(! debug) return;
+  va_list va;
+  va_start(va, fmt);
+  vfprintf(stderr, fmt, va);
+  putchar('\n');
+  va_end(va);
+}
+
+void *emalloc(size_t size) {
+  void *ptr = malloc(size);
+  if(!ptr) {
+    perror("malloc");
+    exit(EXIT_FAILURE);
+  }
+  return ptr;
+}
+
+/* }}} */
+/* {{{ print_users */
+
+void print_users(SilcChannelEntry channel) 
+{
+  int len = 0;
+  char *user, *mode, *msg = emalloc(1);
+  NULL_TEST(msg);
+  msg[0]=0;
+  SilcClientEntry user_entry;
+  SilcChannelUser cuser;
+  SilcHashTableList ch;
+
+  silc_hash_table_list(channel->user_list, &ch);
+  while (silc_hash_table_get(&ch, (void *)&user_entry, (void *)&cuser)) {
+    mode = silc_client_chumode_char(cuser->mode);
+    silc_asprintf(&user, "[%s%s] ",  mode ? mode : "", user_entry->nickname);
+    len += strlen(user_entry->nickname) + strlen(mode ? mode : "")+4;
+    msg = realloc(msg, len);
+    msg = strcat(msg, user);
+
+    silc_free(user);
+    silc_free(mode);
+  }
+  print_out(channel->channel_name, msg);
+  silc_free(msg);
+}
+
+/* }}} */
+/* {{{ sig_handler */
+void 
+sig_handler(int sig)
+{
+  if(sig == SIGINT || sig == SIGTERM ){
+    if(silc_client->detach_on_signal)
+      silc_client_command_call(silc_client->client, silc_client->conn, "detach", NULL);
+    else
+      silc_client_command_call(silc_client->client, silc_client->conn, "quit Leaving", NULL);
+  }
+  silc_schedule_unset_listen_fd(silc_client->client->schedule, buddyfd);
+  silc_schedule_task_del_by_fd(silc_client->client->schedule, buddyfd);
+  close(buddyfd);
+  buddyfd = 0;
+  int i;
+  for (i = 0; i < MAX_CONNS; i++){
+    if(!buddy_conns[i])
+      continue;
+    close(buddy_conns[i]);
+    buddy_conns[i] = 0;
+  }  
+  char *fd;
+  silc_asprintf(&fd, "%s/buddylist", ircdir);
+  unlink(fd);
+  free(fd);
+}
+
+/* }}} */
+/* {{{ UTF-8 <-> Local */
+int 
+LocalToUtf8 (char *from, char **to) 
+{
+  /* Convert Char * to Utf-8 */
+  int len = silc_utf8_encoded_len((unsigned char *)from, strlen(from),
+				  SILC_STRING_LOCALE);
+  *to = calloc(len + 1, sizeof(**to));
+  NULL_TEST_ARG(*to,FALSE);
+  silc_utf8_encode((unsigned char *)from, strlen(from), SILC_STRING_LOCALE,
+		   (unsigned char *)*to, len);
+  return len;
+}
+
+int
+Utf8ToLocal (char *from, char **to) 
+{
+  /* Convert Char * to Local */
+  int len = silc_utf8_decoded_len((unsigned char *)from, strlen(from),
+				  SILC_STRING_LOCALE);
+  *to = calloc(len + 1, sizeof(**to));
+  NULL_TEST_ARG(*to,FALSE);
+  silc_utf8_decode((unsigned char *)from, strlen(from), SILC_STRING_LOCALE,
+		   (unsigned char *)*to, len);
+  return len;
+}
+
+/* }}} */
+/* {{{ silc_localip */
+char *
+silc_localip(void)
+{
+  if (silc_client->conn) {
+    SilcSocket socket;
+    SilcStream stream;
+    char *ip;
+    /* Yes SilcToolkit 1.1 is much easier than 1.0 */
+    stream = silc_packet_stream_get_stream(silc_client->conn->stream);
+    silc_socket_stream_get_info(stream, &socket, NULL, NULL, NULL);
+    silc_net_check_local_by_sock(socket, NULL, &ip);
+    return ip;
+  } else return NULL;
+}
+/* }}} */
+/* {{{ proc_channels_input */
+void 
+proc_channels_input(Channel *c, char *buf) 
+{
+  char *msg;
+  int len = LocalToUtf8(buf, &msg);
+  Channel *ch;
+  /* Commands */
+  if(buf[0]=='/') {
+    /* Join */
+    if(buf[1]=='j' && buf[2] == ' '){
+      DEBUG("Input: JOIN");
+      for(ch = channels; ch; ch = ch->next)
+	if(! strcmp(&buf[3], ch->silc->channel_name))
+	  return; /* Already handled */
+      silc_client_command_call(silc_client->client, silc_client->conn, NULL, 
+              "JOIN", lower(&buf[3]), NULL);
+    }
+    /* ChanInfo */
+    else if(! strncmp(&buf[1], "chaninfo", 8)) {
+        if(c->silc->channel_name[0] == 0){
+            print_out("", "-!?- The master channel is not a real channel");
+        }
+        else {
+            if(strlen(&buf[9]) > 2) {
+                if (! strncmp(&buf[10], "topic", 5)) {
+                    print_out(c->silc->channel_name, "-?!- Topic: %s",
+                            c->silc->topic?c->silc->topic:"None");
+                }
+                else if (!strncmp(&buf[10], "mode", 4)) {
+                    char *str;
+                    str = silc_client_chmode(c->silc->mode, c->silc->cipher,
+                                             c->silc->hmac);
+                    print_out(c->silc->channel_name, "-?!- Channel Mode: %s", 
+                            str ? str : "None");
+                    silc_free(str);
+                }
+                else 
+                    print_out(c->silc->channel_name, 
+                            "-!- Error: /chaninfo [<topic/mode>]");
+            }
+            else {
+                char *str;
+                str = silc_client_chmode(c->silc->mode, c->silc->cipher,
+                                         c->silc->hmac);
+                print_out(c->silc->channel_name, "-?!- Name: %s",  
+                        c->silc->channel_name);
+                print_out(c->silc->channel_name, "-?!- Topic: %s",
+                        c->silc->topic ? c->silc->topic : "None");
+                print_out(c->silc->channel_name, "-?!- Channel Mode: %s", 
+                        str ? str : "None");
+                silc_free(str);
+            }
+        }
+    }
+    /* Leave */
+    else if (buf[1]=='l' &&  ( buf[2] == ' ' || strlen(buf)==2)) {
+      DEBUG("Input: LEAVE");
+      if ( buf[2] == ' ') {
+	silc_client_command_call(silc_client->client, silc_client->conn, NULL, 
+                "LEAVE", &buf[3], NULL);
+      }
+      else if(strlen(buf) == 2)
+	if (strlen(c->silc->channel_name) != 0) {
+	  silc_client_command_call(silc_client->client, silc_client->conn, 
+                  NULL, "LEAVE", c->silc->channel_name, NULL);
+	}
+    }
+    else if ((buf[1] ==  'n' && buf[2] == ' ') || !strcmp(&buf[1], "nick")) {
+      DEBUG("Input: NICK");
+      buf=strchr(&buf[1], ' ')+1;
+      silc_client_command_call(silc_client->client, silc_client->conn, NULL, 
+                               "NICK", buf, NULL);
+    }
+    else if (!strncmp("update", &buf[1],6)) {
+      update_buddylist();
+      refresh_buddylist();
+    }
+    else if (!strncmp("me ", &buf[1], 3) && strlen(&buf[1])>3){
+      DEBUG("Input: ACTION");
+      if (strlen(c->silc->channel_name) != 0) {
+	silc_client_send_channel_message(silc_client->client, silc_client->conn, 
+                                         c->silc, NULL, SILC_MESSAGE_FLAG_UTF8
+					 | SILC_MESSAGE_FLAG_ACTION
+					 | (silc_client->sign ? 
+                                            SILC_MESSAGE_FLAG_SIGNED : 0),
+                                         silc_client->hash,
+					 (unsigned char *)&msg[4], len);
+	print_out(c->silc->channel_name, "%s* %s %s", silc_client->sign ? 
+                  "[S] " : "", silc_client->conn->local_entry->nickname, 
+                  &msg[4]);
+      }
+    }
+    /* file */
+    else if (!strncmp("file ", &buf[1], 5)){
+      Transfer *t;
+      if (!strncmp("list", &buf[6], 4)){
+	if(!transfers)
+	  print_out("", "-!- No file transfers in the list");
+	else
+	  print_out("", "-?!- Number       User                Type            Status");
+	for (t = transfers; t; t = t->next) {
+	  char *status;
+	  if (t->status == FILE_STATUS_WAIT)
+	    status="waiting";
+	  else if (t->status == FILE_STATUS_RUN)
+	    status="running";
+	  else if (t->status == FILE_STATUS_ERR)
+	    status="error";
+	  else if (t->status == FILE_STATUS_COMP)
+	    status="complete";
+	  print_out("", "-?!-    %-5d    %-10s          %-10s        %-10s", 
+                    t->number, t->silc->nickname,
+		    t->type == FILE_TYPE_IN ? "incoming" : "outgoing", status);
+	}
+      }
+      else if(!strncmp("accept ", &buf[6], 7)) {
+	DEBUG("File: ACCEPT");
+	int num = atoi(&buf[13]);
+	for(t = transfers; t; t = t->next)
+	  if(num == t->number)
+	    break;
+	if(!t) {
+	  print_out("", "-!- No such File transfer");
+	  return;
+	}
+        char *path;
+        silc_asprintf(&path, "%s/", getenv("HOME"));
+	create_dirtree(path);
+
+        SilcClientConnectionParams params;
+        memset(&params, 0, sizeof(params));
+        params.local_ip = silc_localip();
+        params.no_authentication = TRUE;
+
+	int res = silc_client_file_receive(silc_client->client, silc_client->conn,
+                                           &params, silc_client->pubkey, 
+                                           silc_client->privkey, file_transfer, 
+                                           NULL, path, t->id, NULL, NULL);
+	if(res != SILC_CLIENT_FILE_OK){
+	  print_out("", "-!- Error: Couldn't start filetransfer");
+	  return;
+	}
+      }
+      else if(!strncmp("send ", &buf[6], 5)) {
+	DEBUG("File: SENT");
+	char **argv;
+	SilcUInt32 *argv_lens, *argv_types, argc, id;
+	SilcClientEntry client;
+	int no_bind = FALSE;
+	silc_parse_command_line((unsigned char *)buf, (void *)&argv, 
+                                &argv_lens, &argv_types, &argc, 5);
+	if (argc < 4) {
+	  print_out("", "-!- File: /file send <nick> <path>");
+	  return;
+	}
+	if (argc == 5)
+	  if (!strcmp("-no-listener", argv[4]))
+	      no_bind = TRUE;
+	client = silc_client_get_client_entry(argv[2]);
+	if(!silc_file_size(argv[3])) {
+	  print_out("", "-!- File: File doesn't exists or is 0 bytes long");
+	  return;
+	}
+        SilcClientConnectionParams params;
+        memset(&params, 0, sizeof(params));
+        if (! no_bind)
+          params.local_ip = silc_localip();
+        params.no_authentication = TRUE;
+
+	int res = silc_client_file_send(silc_client->client, silc_client->conn, 
+                                        client, &params, silc_client->pubkey,
+                                        silc_client->privkey, file_transfer, NULL, 
+                                        argv[3], &id);
+	if(res != SILC_CLIENT_FILE_OK){
+	  print_out("", "-!- Error: Couldn't start filetransfer");
+	  return;
+	}
+	add_transfer(transfer_count, id, client, FILE_TYPE_OUT);
+	print_out("","-!- File: transfer request sent to %s for %s", 
+                  client->nickname, argv[3]);
+	transfer_count++;
+      }
+      else if(!strncmp("close ", &buf[6], 6)) {
+	DEBUG("File: CLOSE");
+	int num = atoi(&buf[12]);
+	for(t = transfers; t; t = t->next)
+	  if(num == t->number){
+	    silc_client_file_close(silc_client->client, silc_client->conn,
+                                   t->id);
+	    print_out("", "-!- File: file transfer closed %d", t->number);
+	    rm_transfer(t);
+	    return;
+	  }
+	print_out("", "-!- No such File transfer");
+      }
+    }
+    /* names */
+    else if (!strncmp("names", &buf[1], 5)){
+      DEBUG("Input: NAMES");
+      if (! strlen(c->silc->channel_name))
+	return;/* Master Channel */
+
+      print_users(c->silc);
+    }
+    /* Starting a new Query */
+    else if (!strncmp("query ", &buf[1], 6)){
+      char *name;
+      SilcClientEntry recv;
+      name = &buf[7];
+      recv = silc_client_get_client_entry(name);
+      if(!recv)
+	return;
+      add_query(recv);
+    }
+    /* Messages */
+    else if (!strncmp("msg ", &buf[1], 4)) {
+      DEBUG("Input: PRIVATE MESSAGE");
+      char *name, *tmp;
+      SilcClientEntry recv;
+      name = &buf[5];
+      msg = strchr(name, ' ');
+      if (!msg) {
+	print_out(c->silc->channel_name, 
+                  "-!- Error: /msg <nickname[@server]> <message>");
+	return;
+      }
+      msg[0] = 0;
+      if(!++msg){
+	print_out(c->silc->channel_name, 
+                  "-!- Error: /msg <nickname[@server]> <message>");
+	return;
+      }
+      if(!msg || ! strlen(msg)){
+	  print_out(c->silc->channel_name, 
+                    "-!- Error: /msg <nickname[@server]> <message>");
+	  return;
+      }
+      recv = silc_client_get_client_entry(name);
+      if(!recv)
+	return;
+      LocalToUtf8(msg, &tmp);
+
+      if (!silc_client_send_private_message(silc_client->client, 
+                                            silc_client->conn, recv,
+                                            SILC_MESSAGE_FLAG_UTF8
+                                            | (silc_client->sign ? 
+                                               SILC_MESSAGE_FLAG_SIGNED : 0),
+                                            silc_client->hash,
+					    (unsigned char *)tmp, strlen(tmp))){
+	print_out("", "-!- Error: Couldn't send private message");
+      }
+      else {
+	print_out("", ">%s< %s", recv->nickname, tmp);
+      }
+      free(tmp);
+      return;
+    }
+    else if (!strncmp("set ", &buf[1], 4)) {
+      /* Set Variabeles */
+      if (!strncmp("signed ", &buf[5], 7)) {
+	if (!strncmp("on", &buf[12], 2)){
+	  silc_client->sign = TRUE;
+	  print_out(c->silc->channel_name, "-!- Signing Messages: on");
+	}
+	else if (!strncmp("off", &buf[12], 3)){
+	  silc_client->sign = FALSE;
+	  print_out(c->silc->channel_name, "-!- Signing Messages: off");
+	}
+	else
+	  print_out(c->silc->channel_name, "-!- Error: False Argument");
+      }
+      else if (!strncmp("signal_detach ", &buf[5], 14)) {
+	if (!strncmp("on", &buf[19], 2)){
+	  silc_client->detach_on_signal = TRUE;
+	  print_out(c->silc->channel_name, "-!- Detach on Signal: on");
+	}
+	else if (!strncmp("off", &buf[19], 3)){
+	  silc_client->detach_on_signal = FALSE;
+	  print_out(c->silc->channel_name, "-!- Detach on Signal: off");
+	}
+	else
+	  print_out(c->silc->channel_name, "-!- Error: False Argument");
+      }
+      else if (!strncmp("auto_away ", &buf[5], 10)) {
+	if (!strncmp("on", &buf[15], 2)){
+	  silc_client->auto_away = TRUE;
+	  print_out(c->silc->channel_name, "-!- Auto away: on");
+	}
+	else if (!strncmp("off", &buf[15], 3)){
+	  silc_client->auto_away = FALSE;
+	  print_out(c->silc->channel_name, "-!- Auto away: off");
+	}
+	else
+	  print_out(c->silc->channel_name, "-!- Error: False Argument");
+      }
+      else
+	print_out(c->silc->channel_name, "-!- Error: False Argument");
+    }
+
+    /* MIME command */
+    else if (!strncmp("mime ", &buf[1], 5)) {
+      unsigned int i, b = FALSE;
+      char **argv;
+      SilcUInt32 *argv_lens, *argv_types, argc;
+      silc_parse_command_line((unsigned char *)buf,
+			      (void *)&argv, &argv_lens,
+			      &argv_types, &argc, 4);
+      if (argc < 2) {
+	print_out(c->silc->channel_name, "-!- Error: /mime "
+                  "<mimetype> [-buffer]");
+	return;
+      }
+      for (i = 2; i < argc; i++) {
+	if (!strcmp("-buffer", argv[i]))
+	  b = TRUE;
+      }
+
+      si_open_mime(c, CHANNEL, argv[1], b);
+      return;
+    }
+
+    else {
+      DEBUG("Input: SENT_COMMAND: %s", &buf[1]);
+      silc_client_command_call(silc_client->client, silc_client->conn, 
+                               &buf[1], NULL);
+    }
+  }
+
+  else {
+    if(strlen(msg)!=0) {
+
+      if (strlen(c->silc->channel_name)!=0) {
+	DEBUG("Input: SENT");
+	last_input = time(NULL);
+	if(silc_client->conn->local_entry->mode & SILC_UMODE_GONE
+	   || silc_client->conn->local_entry->mode & SILC_UMODE_INDISPOSED)
+	  silc_client_command_call(silc_client->client, silc_client->conn, 
+                                   "umode -gi", NULL);
+	silc_client_send_channel_message(silc_client->client, 
+                                         silc_client->conn, c->silc,
+                                         NULL, SILC_MESSAGE_FLAG_UTF8
+					 | (silc_client->sign ? 
+                                            SILC_MESSAGE_FLAG_SIGNED : 0),
+					 silc_client->hash,
+                                         (unsigned char *)msg, len);
+	/* Write it to the Channel */
+	SilcChannelUser cuser;
+	cuser = silc_client_on_channel(c->silc, silc_client->conn->local_entry);
+	char *str = silc_client_chumode_char(cuser->mode);
+	print_out(c->silc->channel_name, "%s<%s%s> %s",
+		  silc_client->sign ? "[S] " : "",
+		  str ? str : " ",
+		  silc_client->conn->local_entry->nickname,
+		  msg);
+	free(str);
+      }
+    }
+  }
+  free(msg);
+}
+
+/* }}} */
+/* {{{ proc_queries_input */
+
+void 
+proc_queries_input (Query *peer, char *buf ) 
+{
+  char *msg;
+  char *path;
+  LocalToUtf8((char *)buf, &msg);
+  silc_asprintf(&path, "query/%s", peer->silc->nickname);
+  if ((strlen(buf) == 2 && !strcmp("/l", buf)) || (strlen(buf)>2 && !strncmp("/l ", buf, 3))) {
+    /* Close the query */
+    print_out(path, "-!- You closed the query");
+    rm_query(peer);
+  }
+
+  /* MIME command */
+  else if (! strncmp("mime ", &buf[1], 5)) {
+    unsigned int i, b = FALSE;
+    char **argv;
+    SilcUInt32 *argv_lens, *argv_types, argc;
+    silc_parse_command_line((unsigned char *)buf,
+			    (void *)&argv, &argv_lens,
+			    &argv_types, &argc, 4);
+    if (argc < 2) {
+      print_out(path, "-!- Error: /mime <mimetype> [-buffer]");
+      return;
+    }
+    for (i = 2; i < argc; i++) {
+      if (!strcmp("-buffer", argv[i]))
+	b = TRUE;
+    }
+
+    si_open_mime(peer, QUERY, argv[1], b);
+    return;
+  }
+
+  else {
+    if (!silc_client_send_private_message(silc_client->client, 
+                                          silc_client->conn, peer->silc,
+					  SILC_MESSAGE_FLAG_UTF8 
+                                          | (silc_client->sign ? 
+                                             SILC_MESSAGE_FLAG_SIGNED : 0),
+                                          silc_client->hash,
+					  (unsigned char *)msg, strlen(msg))){
+      print_out(path,  "-!- Error: Couldn't send private message");
+    }
+    /* Write it to the Query */
+    print_out(path, "<%s> %s", silc_client->conn->local_entry->nickname, msg);
+  }
+  free(msg);
+  silc_free(path);
+  DEBUG("Query: SENT");
+}
+
+/* }}} */
+/* {{{ proc_watch */
+
+void 
+proc_watch(SilcClientEntry client, SilcUInt32 mode, SilcNotifyType type)
+{
+  char *str;
+  switch(type) {
+  case SILC_NOTIFY_TYPE_UMODE_CHANGE:
+    str = silc_client_umode(mode);
+    add_buddy(client);
+    print_out("", "-!- Watch: %s new user mode is: %s", client->nickname, str);
+    free(str);
+    break;
+  case SILC_NOTIFY_TYPE_KILLED:
+    rm_buddy(client);
+    print_out("", "-!- Watch: %s was killed from the network", client->nickname);
+    break;
+  case SILC_NOTIFY_TYPE_SIGNOFF:
+    rm_buddy(client);
+    print_out("", "-!- Watch: %s quit from network", client->nickname);
+    break;
+  case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+    rm_buddy(client);
+    print_out("", "-!- Watch: %s was quit from network trough a server signoff", client->nickname);
+    break;
+  case SILC_NOTIFY_TYPE_NONE:
+    add_buddy(client);
+    print_out("", "-!- Watch: %s is online now", client->nickname);
+    break;
+  default:
+    DEBUG("Error: Unimplemented Watch Type: %d", type);
+  }
+  refresh_buddylist();
+}
+
+/* }}} */
+/* {{{ print_out */
+static void 
+print_out(char *channel, char *buf, ...)
+{
+        static char outfile[256];
+        FILE *out;
+        static char buft[8];
+        time_t t = time(0);
+        char *tmp = NULL;
+        char *msg;
+        va_list va;
+        va_start(va, buf);
+
+        create_filepath(outfile, sizeof(outfile), channel, "out");
+        out = fopen(outfile, "a");
+        silc_vasprintf(&tmp, buf, va);
+        Utf8ToLocal(tmp ? tmp : "", &msg);
+
+        strftime(buft, sizeof(buft), "%R ", localtime(&t));
+        /* Output */
+        fprintf(out, "%s%s\n", buft, msg);
+        fclose(out);
+        free(msg);
+        silc_free(tmp);
+        va_end(va);
+}
+/* }}} */
+/* {{{ get_scc_name_by_id ( Server, Channel, Client )*/
+
+char *
+get_scc_name_by_id(int id, void *record) 
+{
+  char *str;
+  SilcClientEntry sender;
+  SilcChannelEntry channel;
+  SilcServerEntry server;
+  if (id == SILC_ID_CLIENT) {
+    sender = (SilcClientEntry) record;
+    silc_asprintf(&str, "%s", sender->nickname);
+  }
+  else if (id == SILC_ID_SERVER) {
+    server = (SilcServerEntry)record;
+    silc_asprintf(&str, "%s (Server)", server->server_name);
+  }
+  else {
+    channel=(SilcChannelEntry)sender;
+    silc_asprintf(&str, "%s (Channel)", channel->channel_name);
+  }
+  return str;
+}
+
+/* }}} */
+/* {{{ silc_client_umode */
+
+char *
+silc_client_umode(SilcUInt32 mode) 
+{
+  char *stat = emalloc(15);
+  stat[0] = 0;
+  if (mode & SILC_UMODE_GONE)
+    strcat(stat,"G");
+  if (mode & SILC_UMODE_INDISPOSED)
+    strcat(stat,"I");
+  if (mode & SILC_UMODE_BUSY)
+    strcat(stat,"B");
+  if (mode & SILC_UMODE_PAGE)
+    strcat(stat,"P");
+  if (mode & SILC_UMODE_HYPER)
+    strcat(stat,"H");
+  if (mode & SILC_UMODE_SERVER_OPERATOR)
+    strcat(stat,"Os");
+  if (mode & SILC_UMODE_ROUTER_OPERATOR)
+    strcat(stat,"Or");
+  if (mode & SILC_UMODE_BLOCK_PRIVMSG)
+    strcat(stat,"Np");
+  if (mode & SILC_UMODE_DETACHED)
+    strcat(stat,"D");
+  if (mode & SILC_UMODE_REJECT_WATCHING)
+    strcat(stat,"Nw");
+  if (mode & SILC_UMODE_BLOCK_INVITE)
+    strcat(stat,"Ni");
+  if (mode & SILC_UMODE_ROBOT)
+    strcat(stat,"R");
+  if (mode & SILC_UMODE_ANONYMOUS)
+    strcat(stat,"?");
+  if (!strlen(stat))
+    strcat(stat,"A");
+
+  return stat;
+}
+
+/* }}} */
+/* {{{ silc_verify_message */
+char *
+silc_verify_message(SilcClientEntry sender, SilcMessagePayload message) 
+{
+  char *retval;
+  silc_asprintf(&retval, "[?] ");
+
+  const unsigned char *pk_data;
+  SilcUInt32 pk_datalen;
+  unsigned int i;
+  char *fpKey;
+  SilcPublicKey pk = silc_message_signed_get_public_key(message, &pk_data,
+                                                        &pk_datalen);
+  if (!pk) {
+    if(sender->fingerprint[0]){
+      fpKey = silc_fingerprint(sender->fingerprint, 
+                               sizeof(sender->fingerprint));
+    }
+    else
+      return retval;
+  }
+  else
+     fpKey = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
+
+  char *fp = emalloc(strlen(fpKey) + 1);
+  for (i = 0; i < strlen(fpKey); i++){
+    if (fpKey[i]==' ')
+      fp[i]='_';
+    else
+      fp[i]=fpKey[i];
+  }
+  fp[i]=0;
+  silc_free(fpKey);
+
+  DIR *dir;
+  char *path;
+  silc_asprintf(&path, "%s/.silc/clientkeys", (char *)getenv("HOME"));
+  create_dirtree(path);
+  dir = opendir(path);
+  struct dirent *entry;
+  while((entry = readdir(dir))) {
+    if(!strncmp(entry->d_name, fp, strlen(fp))){
+      silc_free(path);
+      silc_asprintf(&path, "%s/.silc/clientkeys/%s", 
+                    (char *)getenv("HOME"), entry->d_name);
+      silc_free(fp);
+      SilcPublicKey cached_pk = NULL;
+
+      /* try to load the file */
+      if (!silc_pkcs_load_public_key(path, &cached_pk))
+	if(!pk)
+	  return retval;
+      if(cached_pk){
+	if(pk)
+	  silc_pkcs_public_key_free(pk);
+	pk = cached_pk;
+      }
+      /* the public key is now in pk, our "level of trust" in ret */
+      if ((pk) && silc_message_signed_verify(message, pk, silc_client->hash)
+          != SILC_AUTH_OK)
+	sprintf(retval, "[F] ");
+      else
+	sprintf(retval, "[S] ");
+      if (pk)
+	silc_pkcs_public_key_free(pk);
+      return retval;
+    }
+  }
+  silc_free(fp);
+  return retval;
+}
+/* }}} */
+/* {{{ callback_get_client_entry */
+
+void 
+callback_get_client_entry(SilcClient client,
+                          SilcClientConnection conn,
+                          SilcStatus status,
+                          SilcDList clients,
+                          void *context)
+{
+  if (! silc_dlist_count(clients)) {
+    print_out("", "-!- Error: No such User");
+    resolve_name = (void *) 1;
+    return;
+  }
+  if (silc_dlist_count(clients) > 1) {
+    /* Find client entry */
+    clients = silc_client_get_clients_local(silc_client->client, 
+                                            silc_client->conn,
+					    (char *)context, 
+                                            FALSE);
+    if(! silc_dlist_count(clients)){
+      print_out("", "-!- Error: No such User");
+      resolve_name = (void *)1;
+      return;
+    }
+  }
+  silc_dlist_start(clients);
+  resolve_name = silc_dlist_get(clients);
+  return;
+}
+
+/* }}} */
+/* {{{ silc_client_get_client_entry */
+SilcClientEntry 
+silc_client_get_client_entry(const char *nick) 
+{
+  char *nickname;
+  SilcDList clients;
+  /* Find client entry */
+  clients = silc_client_get_clients_local(silc_client->client, 
+                                          silc_client->conn,
+					  nick, FALSE);
+  if(! silc_dlist_count(clients)) {
+    resolve_name = NULL;
+    /* Resolv the name */
+    silc_client_get_clients(silc_client->client,
+			    silc_client->conn,
+			    nickname,NULL,
+                            callback_get_client_entry, 
+                            (char *)nick);
+    while(!resolve_name)
+      run_once();
+    if ((int) resolve_name == 1)
+      return NULL;
+  }
+  else {
+    silc_dlist_start(clients);
+    resolve_name = silc_dlist_get(clients);
+  }
+  return resolve_name;
+}
+/* }}} */
+/* {{{ file_transfer */
+void 
+file_transfer(SilcClient client,
+              SilcClientConnection conn,
+              SilcClientMonitorStatus status,
+              SilcClientFileError error,
+              SilcUInt64 offset,
+              SilcUInt64 filesize,
+              SilcClientEntry client_entry,
+              SilcUInt32 session_id,
+              const char *filepath,
+              void *context) 
+{
+  Transfer *t;
+  for (t=transfers; t; t=t->next)
+    if( t->id == session_id )
+      break;
+  if ( offset && filesize )
+    t->percent = (float) ((double)offset / (double)filesize) * (double)100.0;
+
+  if (status == SILC_CLIENT_FILE_MONITOR_ERROR) {
+    if (error == SILC_CLIENT_FILE_NO_SUCH_FILE)
+      print_out("", "-!- Error: There is no such file (Number: %d)",t->number);
+    else if(error == SILC_CLIENT_FILE_PERMISSION_DENIED)
+      print_out("", "-!- Error: Permission denied (Number: %d)",t->number);
+    else
+      print_out("", "-!- Error: File transfer failed (Number: %d)",t->number);
+    t->status=FILE_STATUS_ERR;
+    return;
+  }
+
+  else if (status == SILC_CLIENT_FILE_MONITOR_KEY_AGREEMENT)
+    print_out("", "-!- File: Negotiating keys for file transfer %d", t->number);
+  else if (status == SILC_CLIENT_FILE_MONITOR_SEND  || status == SILC_CLIENT_FILE_MONITOR_RECEIVE) {
+    if(offset==0) {
+      t->starttime=time(NULL);
+      print_out("", "-!- File: Started file transfer with %d", t->number);
+      t->status=FILE_STATUS_RUN;
+    }
+    else if (offset == filesize) {
+      unsigned long delta=time(NULL)-t->starttime;
+      float kps;
+
+      if (delta)
+	kps = (double)((offset / (double)delta) + 1023) / (double)1024;
+      else
+	kps = (double)(offset + 1023) / (double)1024;
+      print_out("", "-!- File: Completed file transfer %d [%.2f kB/s]", t->number, kps);
+      if(status== SILC_CLIENT_FILE_MONITOR_RECEIVE)
+	print_out("", "-!- File: saved to: %s", filepath);
+      t->status=FILE_STATUS_COMP;
+    }
+  }
+
+
+}
+/* }}} */
+/* {{{ run_once */
+
+void 
+run_once() 
+{
+  /* Select the different fifo's */
+  Channel *c;
+  Query *q;
+  int r, maxfd=0, i;
+  fd_set rd;
+  struct timeval tv;
+  if (silc_client->auto_away){
+    if ((time(NULL) - last_input) >= 600){
+      if(! (silc_client->conn->local_entry->mode & SILC_UMODE_INDISPOSED)){
+	silc_client_command_call(silc_client->client, silc_client->conn, 
+                                 "umode +i", NULL);
+	last_input = time(NULL);
+      }
+    }
+    if ((time(NULL) - last_input) >= 1200){
+      if(! (silc_client->conn->local_entry->mode & SILC_UMODE_GONE)){
+	silc_client_command_call(silc_client->client, silc_client->conn, 
+                                 "umode +g", NULL);
+	last_input = time(NULL);
+      }
+    }
+  }
+  FD_ZERO(&rd);
+  for(c = channels; c; c = c->next) {
+    if(maxfd < c->fd)
+      maxfd = c->fd;
+    FD_SET(c->fd, &rd);
+  }
+  for(q = queries; q; q = q->next) {
+    if(maxfd < q->fd)
+      maxfd = q->fd;
+    FD_SET(q->fd, &rd);
+  }
+  for(i = 0; i < MAX_CONNS; i++){
+    if(!buddy_conns[i])
+      continue;
+    if(maxfd < buddy_conns[i])
+      maxfd = buddy_conns[i];
+    FD_SET(buddy_conns[i], &rd);
+  }
+  tv.tv_sec = 0;
+  tv.tv_usec = 1;
+  r = select(maxfd + 1, &rd, 0, 0, &tv);
+  if(r < 0) {
+    if(errno == EINTR)
+      return;
+    perror("si: error on select()");
+    exit(EXIT_FAILURE);
+  }
+  for(c = channels; c; c = c->next)
+    if(FD_ISSET(c->fd, &rd))
+      handle_channels_input(c);
+  for(q = queries; q; q = q->next)
+    if(FD_ISSET(q->fd, &rd))
+      handle_query_input(q);
+  for(i=0; i<MAX_CONNS; i++){
+    if(! buddy_conns[i])
+      continue;
+    if(FD_ISSET(buddy_conns[i], &rd))
+      si_handle_buddy_conn_input(buddy_conns[i]);
+      }
+  /* Run the Silc Client one Time */
+  silc_client_run_one(silc_client->client);
+}
+
+/* }}} */
+/* {{{ run */
+
+int 
+run(void)
+{
+  int fd;
+  time_t conn_timeout;
+  SilcClientParams params;
+  SilcClientConnectionParams conn_params;
+  silc_client = emalloc(sizeof(*silc_client));
+  /* ClientParams */
+  memset(&params, 0, sizeof(params));
+  strcat(params.nickname_format, "%n@%h%a");
+
+
+  silc_client->client = silc_client_alloc(&ops, &params, silc_client, NULL);
+  NULL_TEST_ARG(silc_client->client, 1);
+
+  /* Set Signed Messages per Default to off */
+  silc_client->sign = FALSE;
+  silc_client->auto_away = FALSE;
+  last_input = time(NULL);
+
+  /* Now we initialize the client. */
+  if (!silc_client_init(silc_client->client, silc_get_username(), 
+                        silc_net_localhost(),
+                        realname, NULL, NULL)) {
+    perror("si: Could not init SILC client");
+    return 1;
+  }
+  /* run silc client one time to initialize it */
+  silc_client_run_one(silc_client->client);
+
+  silc_hash_alloc((const unsigned char *)"sha1", &silc_client->hash);
+
+  /* Load Key's from $HOME/.silc/ */
+  char *silc_prv;
+  char *silc_pub;
+  
+  silc_asprintf(&silc_prv, "%s/.silc/private_key.prv", (char *)getenv("HOME"));
+  silc_asprintf(&silc_pub, "%s/.silc/public_key.pub", (char *)getenv("HOME"));
+  if (!silc_load_key_pair(silc_pub, silc_prv, "", &silc_client->pubkey, 
+                          &silc_client->privkey)) {
+    /* Generate new Key's */
+    fprintf(stdout, "si: Key pair does not exist, generating it.\n");
+    if (!silc_create_key_pair("rsa", 2048, silc_pub, silc_prv, NULL, "",
+                              &silc_client->pubkey, &silc_client->privkey,
+                              FALSE)) {
+      perror("si: Could not generated key pair");
+      return 1;
+    }
+  }
+  silc_free(silc_prv);
+  silc_free(silc_pub);
+
+  /* create path */
+  silc_asprintf(&ircdir, "%s/%s", prefix, host);
+  create_dirtree(ircdir);
+
+  /* Maser Channel */
+  SilcChannelEntry master;
+  master = calloc(1, sizeof(*master));
+  NULL_TEST_ARG(master, 1);
+
+  master->channel_name = "";
+  add_channel(master);
+
+  /* Restoring Detached data */
+  char *filename;
+  silc_asprintf(&filename, "%s/.silc/session.%s", getenv("HOME"), host);
+
+  memset((void *) &conn_params, 0, sizeof(conn_params));
+  conn_params.detach_data_len = 0;
+  conn_params.detach_data = (unsigned char *)
+    silc_file_readfile(filename, &conn_params.detach_data_len);
+  silc_free(filename);
+  conn_params.pfs = TRUE;
+  conn_params.nickname = username;
+
+  printf("%s %s\n", host, username);
+  /* Start connecting to server.  This is asynchronous connecting so the
+     connection is actually created later after we run the client. */
+  if(! silc_client_connect_to_server(silc_client->client, &conn_params, 
+                                     silc_client->pubkey, silc_client->privkey,
+                                     host, port, silc_connection_cb, NULL)){
+    fprintf(stderr, "si: Couldn't connect to server\n");
+    exit(EXIT_FAILURE);
+  }
+
+
+  /* Run it one time */
+  conn_timeout = time(NULL); 
+  while(!connected) {
+    silc_client_run_one(silc_client->client);
+    if ((time(NULL) - conn_timeout ) > 15) {
+      fprintf(stderr, "si: Couldn't connect to server (Timeout)\n");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  /* Install the SigHandler for SIGINT */
+  signal(SIGINT, sig_handler);
+  signal(SIGTERM, sig_handler);
+
+  /* Ignore some SIGPIPE */
+  signal(SIGPIPE, SIG_IGN);
+
+  /* Run the init Script */
+  if(init_script){
+    fd=open(init_script, 0);
+    if(fd==-1)
+      perror("si: Couldn't open init script, continuing..");
+    else {
+      Channel *c;
+      char buf[4097];
+      char buf2[4098];
+      /* find master channel */
+      for(c = channels; c; c = c->next)
+	if(!strlen(c->silc->channel_name))
+	  break;
+      while(read_line(fd, 4096, buf)!=-1){
+	snprintf(buf2, 4097, "/%s", buf);
+	proc_channels_input(c, buf2);
+      }
+    }
+  }
+  /* Init the Buddylist */
+  init_buddylist();
+
+  for (;;) {
+    run_once();
+  }
+
+  silc_client_free(silc_client->client);
+  free(silc_client);
+  return 0;
+}
+
+/* }}} */
+
+/* {{{ silc_channel_message */
+static void
+silc_channel_message(SilcClient client, SilcClientConnection conn,
+		     SilcClientEntry sender, SilcChannelEntry channel,
+		     SilcMessagePayload payload,
+		     SilcChannelPrivateKey key,
+		     SilcMessageFlags flags, const unsigned char *content,
+		     SilcUInt32 message_len)
+{
+  /* Write it out*/
+  SilcChannelUser cuser;
+  cuser=silc_client_on_channel(channel, sender);
+  char *str;
+  char *sigstat = NULL;
+
+  if(flags & SILC_MESSAGE_FLAG_SIGNED){
+    sigstat=silc_verify_message(sender,payload);
+  }
+
+  if (flags & SILC_MESSAGE_FLAG_DATA) {
+    /* Process MIME message */
+    SilcMime mime = silc_mime_decode(NULL, content, message_len);
+    si_process_mime(client, conn, sender, channel, payload, key, flags,
+		    mime, FALSE);
+    return;
+  }
+
+  str = silc_client_chumode_char(cuser->mode);
+  if (flags & SILC_MESSAGE_FLAG_ACTION)
+    print_out(channel->channel_name, "%s* %s %s", sigstat?sigstat:"",sender->nickname, (char *)content);
+  else
+    print_out(channel->channel_name, "%s<%s%s> %s", sigstat?sigstat:"", str?str:" ", sender->nickname, (char *)content);
+  free(str);
+}
+/* }}} */
+/* {{{ silc_command */
+static void
+silc_command(SilcClient client, SilcClientConnection conn, bool success,
+             SilcCommand command, SilcStatus status, SilcUInt32 argc,
+             unsigned char **argv)
+{
+  /* If error occurred in client library with our command, print the error */
+  if (status != SILC_STATUS_OK && command != SILC_COMMAND_WATCH){
+    print_out("", "-!- Error: %s: %s",
+	     silc_get_command_name(command),
+	     silc_get_status_message(status));
+  }
+}
+/* }}} */
+/* {{{ silc_command_reply */
+static void
+silc_command_reply(SilcClient client, SilcClientConnection conn,
+		   SilcCommand command, SilcStatus status, SilcStatus error,
+                   va_list va)
+{
+  SilcUInt32 mode, count;
+  SilcChannelEntry channel;
+  SilcClientEntry sender;
+  SilcServerEntry server;
+  SilcHashTableList ch;
+  SilcChannelUser cuser;
+  Channel *c;
+  char *str, *str2;
+  int type;
+  /* If error occurred in client library with our command, print the error */
+  if (SILC_STATUS_IS_ERROR(status) && command != SILC_COMMAND_WATCH)  {
+      print_out("", "-!- Error %s: %s",
+		silc_get_command_name(command),
+		silc_get_status_message(error));
+      return;
+    }
+
+  /* Check for successful JOIN */
+  if (command == SILC_COMMAND_JOIN) {
+    DEBUG("Command: JOIN");
+    (void)va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    add_channel(channel);
+    print_users(channel);
+  }
+  else if (command == SILC_COMMAND_UMODE) {
+    mode=va_arg(va, SilcUInt32);
+    char *stat=silc_client_umode(mode);
+    print_out("", "-!- You changed your user mode to: %s", stat?stat:"");
+    free(stat);
+
+  }
+  else if (command == SILC_COMMAND_LEAVE) {
+    DEBUG("Command: LEAVE");
+    channel = va_arg(va, SilcChannelEntry);
+    print_out("", "-!- You have left the Channel");
+    rm_channel(channel->context);
+  }
+  else if (command == SILC_COMMAND_USERS) {
+    DEBUG("Command: USERS");
+    channel = va_arg(va, SilcChannelEntry);
+    int joined=FALSE;
+    for (c = channels; c; c = c->next)
+      if (!strcmp(c->silc->channel_name, channel->channel_name))
+	joined = TRUE;
+    print_out(joined ? channel->channel_name : "", "-!- Users: ");
+    silc_hash_table_list(channel->user_list, &ch);
+    while (silc_hash_table_get(&ch, (void *)&sender, (void *)&cuser)) {
+      char *stat, *mode;
+      if (!sender->nickname)
+	continue;
+      stat = silc_client_umode(sender->mode);
+      mode = silc_client_chumode_char(cuser->mode);
+      print_out(joined ? channel->channel_name: "" , "-!- %s %s%s %s@%s[%s]",
+                sender->nickname, stat ,mode ? mode : "",
+                sender->username, sender->hostname,
+		sender->realname ? sender->realname : "");
+      free(mode);
+      free(stat);
+    }
+    silc_hash_table_list_reset(&ch);
+  }
+  else if (command == SILC_COMMAND_NICK) {
+    DEBUG("Command: NICK");
+    sender = va_arg(va, SilcClientEntry);
+    for (c=channels; c; c=c->next){
+      print_out(c->silc->channel_name, "-!- Your new nickname is %s", sender->nickname);
+    }
+  }
+  else if (command == SILC_COMMAND_WHOIS) {
+    DEBUG("Command: WHOIS");
+    int len = 2;
+    char *nickname, *username, *realname, *str=malloc(1), *fingerprint;
+    SilcDList channels;
+    SilcUInt32 *user_modes;
+    SilcUInt32 mode, idle;
+    NULL_TEST(str);
+    str[0] = 0;
+    sender = va_arg(va, SilcClientEntry);
+    nickname = va_arg(va, char *);
+    username = va_arg(va, char *);
+    realname = va_arg(va, char *);
+    channels = va_arg(va, SilcDList);
+    mode = va_arg(va, SilcUInt32);
+    idle = va_arg(va, SilcUInt32);
+    fingerprint = va_arg(va, char *);
+    user_modes = va_arg(va, SilcUInt32 *);
+    /* Username etc.*/
+    print_out("", "-?!- Whois: %s@%s (%s)", sender->nickname_normalized, 
+              sender->server, username);
+    print_out("", "-?!- Nickname: %s (%s)", sender->nickname_normalized, 
+              sender->nickname);
+    print_out("", "-?!- Realname: %s", realname);
+    /* Channels */
+    if (channels && user_modes) {
+      int i = 0;
+
+      silc_dlist_start(channels);
+      SilcChannelPayload channel;
+      while ((channel = silc_dlist_get(channels)) != SILC_LIST_END) {
+        SilcUInt32 name_len;
+        char *m = silc_client_chumode_char(user_modes[i++]);
+        char *name = (char *)silc_channel_get_name(channel, &name_len);
+        if (m)
+          len += strlen(m);
+        len += name_len + 2;
+        str = realloc(str, len);
+        NULL_TEST(str);
+        strcat(str, name);
+        if(m)
+          strcat(str, m);
+        strcat(str, " ");
+        silc_free(m);
+      }
+      print_out("", "-?!- Channels: %s", str);
+      silc_free(str);
+    }
+    /* User Mode */
+    if(mode){
+      str=silc_client_umode(mode);
+      print_out("", "-?!- User Mode: %s", str);
+      free(str);
+    }
+    /* Idle */
+    if(idle) {
+      print_out("", "-?!- Idle: %d %s", idle>60?idle/60:idle, idle>60?"minutes":"seconds");
+    }
+    /* Fingerprint */
+    if (fingerprint) {
+      fingerprint = silc_fingerprint((unsigned char *)fingerprint, 20);
+      print_out("", "-?!- Fingerprint: %s", fingerprint);
+      free(fingerprint);
+    }
+  print_out("", "");
+  }
+  else if(command == SILC_COMMAND_LIST) {
+
+    channel = va_arg(va, SilcChannelEntry);
+    if (!channel){
+      print_out("", "-!- Error: There is no such channel on the Network");
+      return;
+    }
+    (void)va_arg(va, void *);
+    str = va_arg(va, char *);
+    count = va_arg(va, SilcUInt32);
+    DEBUG("Status: %d", status);
+    if(status == SILC_STATUS_LIST_START || status==0 )
+      print_out("", "Channel                 Users            Topic");
+    print_out("", "%-25s %-15d %s", channel->channel_name, count, str?str:"");
+  }
+  else if(command == SILC_COMMAND_INFO) {
+    DEBUG("Command: INFO");
+    (void)va_arg(va, void *);
+    str=va_arg(va, char *);
+    str2=va_arg(va, char *);
+    print_out("","-!- Info: %s %s", str, str2);
+  }
+  else if(command == SILC_COMMAND_STATS) {
+    DEBUG("Comman: STATS");
+    SilcClientStats *stats;
+    const char *tmptime;
+    int days, hours, mins, secs;
+
+    stats = va_arg(va, SilcClientStats *);
+
+    tmptime = silc_time_string(stats->starttime);
+    days = stats->uptime / (24 * 60 * 60);
+    stats->uptime -= days * (24 * 60 * 60);
+    hours = stats->uptime / (60 * 60);
+    stats->uptime -= hours * (60 * 60);
+    mins = stats->uptime / 60;
+    stats->uptime -= mins * 60;
+    secs = stats->uptime;
+
+    /* Output */
+    print_out("", "Starttime: %-20s Uptime: %d days %d hours %d "
+              "minutes %d seconds", tmptime, days, hours, mins, secs);
+    print_out("", "Local Clients:          %-5d  Local Channels:         %-5d",
+              stats->my_clients, stats->my_channels);
+    print_out("", "Local Server Operators: %-5d  Local Router Operators: %-5d",
+              stats->my_server_ops, stats->my_router_ops);
+    print_out("", "Cell Clients:           %-5d  Cell Channels:          %-5d"
+              "Cell Servers: %-5d", stats->cell_clients, stats->cell_channels, 
+              stats->cell_servers);
+    print_out("", "Total Clients:          %-5d  Total Channels:         %-5d",
+              stats->clients, stats->channels);
+    print_out("", "Total Servers:          %-5d  Total Routers:          %-5d", 
+              stats->servers, stats->routers);
+    print_out("", "Total Server Operators: %-5d  Total Router Operators: %-5d", 
+              stats->server_ops, stats->router_ops);
+  }
+  else if(command==SILC_COMMAND_GETKEY) {
+    DEBUG("Command: GETKEY");
+    SilcPublicKey key;
+    void *entry;
+    char *filename, *pos;
+    unsigned int i;
+
+    type=va_arg(va, int);
+    entry=va_arg(va, void *);
+    key=va_arg(va, SilcPublicKey);
+    unsigned char *pk;
+    SilcUInt32 pk_len;
+    pk = silc_pkcs_public_key_encode(key, &pk_len);
+    char *fpKey = silc_hash_fingerprint(0, pk, pk_len);
+    char *fp=malloc(strlen(fpKey)+1);
+    NULL_TEST(fp);
+    for (i = 0; i < strlen(fpKey); i++){
+      if (fpKey[i] == ' ')
+	fp[i]='_';
+      else
+	fp[i]=fpKey[i];
+    }
+    fp[i]=0;
+    free(fpKey);
+
+    if(type == SILC_ID_SERVER) {
+      server = (SilcServerEntry)entry;
+      /* $HOME/.silc/clientkeys/fp(name):server */
+      silc_asprintf(&filename, "%s/.silc/incoming_keys/%s(%s):server", 
+                    getenv("HOME"), fp, server->server_name);
+    }
+    else if(type== SILC_ID_CLIENT) {
+     sender=(SilcClientEntry)entry;
+     silc_asprintf(&filename, "%s/.silc/incoming_keys/%s(%s)", 
+                   getenv("HOME"), fp, sender->nickname);
+    }
+    pos = strrchr(filename, '/');
+    pos[0] = 0;
+    create_dirtree(filename);
+    pos[0] = '/';
+    if(!silc_pkcs_save_public_key(filename, key, SILC_PKCS_FILE_BASE64)){
+      print_out("", "-!- Error: Couldn't save public key");
+      return;
+    }
+    print_out("", "-!- Getkey: The Key you had asked, was saved in: %s", filename);
+    silc_free(filename);
+  }
+  else if(command == SILC_COMMAND_WHOWAS) {
+    (void)va_arg(va, SilcClientEntry);
+    char *nickname = va_arg(va, char *);
+    char *username = va_arg(va, char *);
+    char *realname = va_arg(va, char *);
+    print_out("", "-?!- Whowas: %s (%s) [%s]", nickname, username, 
+              realname ? realname : "");
+  }
+  else if(command == SILC_COMMAND_OPER)
+    print_out("", "-!- You are server oper now");
+  else if(command == SILC_COMMAND_SILCOPER)
+    print_out("", "-!- You are router oper now");
+  else if(command == SILC_COMMAND_DETACH) {
+    SilcBuffer detach = va_arg(va, SilcBuffer);
+    char *file;
+    silc_asprintf(&file, "%s/.silc/session.%s", getenv("HOME"), host);
+    silc_file_writefile(file, (char *)silc_buffer_data(detach),
+                        silc_buffer_len(detach));
+    silc_free(file);
+  }
+
+  va_end(va);
+}
+/* }}} */
+/* {{{ silc_connection_cb */
+void 
+silc_connection_cb(SilcClient si,
+                        SilcClientConnection conn,
+                        SilcClientConnectionStatus status,
+                        SilcStatus error,
+                        const char *message,
+                        void *context) 
+{
+  SilcChannelEntry channel;
+  Silc client = si->application;
+  Query *q;
+  Channel *c;
+
+  switch(status) {
+  case SILC_CLIENT_CONN_SUCCESS_RESUME:
+    DEBUG("Connect: RESUME");
+    SilcHashTableList ch;
+    silc_hash_table_list(conn->local_entry->channels, &ch);
+    while (silc_hash_table_get(&ch, (void *)&channel, NULL))
+      add_channel(channel);
+    silc_hash_table_list_reset(&ch);
+
+    char *filename;
+    silc_asprintf(&filename, "%s/.silc/session.%s", getenv("HOME"), host);
+    unlink(filename);
+    free(filename);
+    print_out("", "-!- Resumed old session");
+  case SILC_CLIENT_CONN_SUCCESS:
+    client->conn = conn;
+    connected=1;
+    DEBUG("Connect: Connection succsessful");
+    break;  
+  case SILC_CLIENT_CONN_DISCONNECTED:
+    /* We got disconnected from server */
+    for (c = channels; c; c = c->next)
+      print_out(c->silc->channel_name, "-!- You have left Network [%s]",
+                message ? message : "");
+    for (q = queries; q; q = q->next)
+      print_out(c->silc->channel_name, "-!- You have left Network [%s]", 
+                message ? message : "");
+    DEBUG("Disconnected: %s:%s", silc_get_status_message(status),
+          message ? message : "");
+    exit(0);
+    break;
+  case SILC_CLIENT_CONN_ERROR:
+    print_out("", "Couldn't connect: unknown error");
+    goto error;
+  case SILC_CLIENT_CONN_ERROR_KE:
+    print_out("", "Couldn't connect: key exchange failed");
+    goto error;
+  case SILC_CLIENT_CONN_ERROR_AUTH:
+    print_out("", "Couldn't connect: authenitication failed");
+    goto error;
+  case SILC_CLIENT_CONN_ERROR_RESUME:
+    print_out("", "Couldn't connect: resume error");
+    goto error;
+  case SILC_CLIENT_CONN_ERROR_TIMEOUT:
+    print_out("", "Couldn't connect: timeout error");
+error:
+    fprintf(stderr, "si: Could not connect to server\n");
+    silc_client_close_connection(si, conn);
+    exit(EXIT_FAILURE);
+  }
+}
+/* }}} */
+/* {{{ silc_notify */
+
+static void
+silc_notify(SilcClient client, SilcClientConnection conn,
+	    SilcNotifyType type, ...)
+{
+  char *str, *str2;
+  int id;
+  SilcUInt32 mode;
+  SilcChannelEntry channel, channel2;
+  SilcClientEntry sender, sender2;
+  Channel *c;
+  Query *q;
+  SilcHashTableList ch;
+  va_list va;
+
+  va_start(va, type);
+
+  switch (type) {
+  case SILC_NOTIFY_TYPE_NONE:
+    /* Received something that we are just going to dump to screen. */
+    str = va_arg(va, char *);
+    print_out("", str);
+    break;
+  case SILC_NOTIFY_TYPE_JOIN:
+    /* Joined Channel*/
+    DEBUG("Notify: JOIN");
+    sender = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    print_out(channel->channel_name, "-!- %s [%s@%s] has joined %s", sender->nickname, sender->username,sender->hostname, channel->channel_name);
+    break;
+  case SILC_NOTIFY_TYPE_LEAVE:
+    /* Left Channel */
+    DEBUG("Notify: LEAVE");
+    sender = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    print_out(channel->channel_name, "-!- %s [%s@%s] has left %s", sender->nickname, sender->username,sender->hostname, channel->channel_name);
+    break;
+  case SILC_NOTIFY_TYPE_INVITE:
+    DEBUG("Notify: INVITE");
+    channel = va_arg(va, SilcChannelEntry);
+    char *name=va_arg(va, char *);
+    sender = va_arg(va, SilcClientEntry);
+    print_out("", "-!- You were invited joining the channel %s by %s", channel?channel->channel_name:name, sender->nickname);
+    break;
+  case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+    DEBUG("Notify: SERVER SIGNOFF");
+    SilcDList clients;
+
+    (void)va_arg(va, void *);
+    clients = va_arg(va, SilcDList);
+    silc_dlist_start(clients);
+
+    while((sender = silc_dlist_get(clients))) {
+      silc_hash_table_list(sender->channels, &ch);
+      while (silc_hash_table_get(&ch, (void *)&channel, (void *)&channel2)) {
+	for(c = channels; c; c = c->next)
+	  if(!strcmp(c->silc->channel_name, channel->channel_name))
+	    print_out(channel->channel_name,"-!- %s  has quit [%s]", 
+                      sender->nickname, "server signoff");
+      }
+      silc_hash_table_list_reset(&ch);
+      for (q=queries; q; q=q->next){
+	char *path;
+	silc_asprintf(&path, "query/%s", sender->nickname);
+	print_out(path,"-!- %s  has quit [%s]", sender->nickname, str?str:"");
+	silc_free(path);
+      }
+    }
+    break;
+  case SILC_NOTIFY_TYPE_SIGNOFF:
+    /* Left the Network */
+    DEBUG("Notify: SIGNOFF");
+    sender = va_arg(va, SilcClientEntry);
+    rm_buddy(sender);
+    refresh_buddylist();
+    str = va_arg(va, char *);
+    silc_hash_table_list(sender->channels, &ch);
+    while (silc_hash_table_get(&ch, (void *)&channel, (void *)&channel2)) {
+      for(c=channels; c; c=c->next)
+	if(!strcmp(c->silc->channel_name, channel->channel_name))
+	  print_out(channel->channel_name,"-!- %s  has quit [%s]", 
+                    sender->nickname, str ? str : "");
+    }
+    silc_hash_table_list_reset(&ch);
+    for (q = queries; q; q = q->next){
+      char *path;
+      silc_asprintf(&path, "query/%s", sender->nickname);
+      print_out(path,"-!- %s  has quit [%s]", sender->nickname, str?str:"");
+      silc_free(path);
+    }
+    break;
+  case SILC_NOTIFY_TYPE_TOPIC_SET:
+    /* Changed topic.*/
+    DEBUG("Notify: TOPIC");
+    id = va_arg(va, int);
+    sender = va_arg(va, void *);
+    str2 = va_arg(va, char *);
+    channel = va_arg(va, SilcChannelEntry);
+    str=get_scc_name_by_id(id, sender);
+    print_out(channel->channel_name, "-!- %s has changed topic to: %s", str?str:"", str2);
+    free(str);
+    break;
+  case SILC_NOTIFY_TYPE_NICK_CHANGE:
+    /* Somebody has changed his name */
+    DEBUG("Notify: NICK_CHANGE");
+    char *old_nickname;
+    sender = va_arg(va, SilcClientEntry);
+    old_nickname = va_arg(va, char *);
+
+    silc_hash_table_list(sender2->channels, &ch);
+    while (silc_hash_table_get(&ch, (void *)&channel, (void *)&channel2)) {
+      for(c=channels; c; c=c->next)
+	if(!strcmp(c->silc->channel_name, channel->channel_name))
+	  print_out(channel->channel_name,  "-!- %s is known as: %s", 
+                    old_nickname, sender->nickname);
+    }
+    silc_hash_table_list_reset(&ch);
+    break;
+  case SILC_NOTIFY_TYPE_MOTD:
+    /* Received the Message of the Day from the server. */
+    DEBUG("Notify: MOTD");
+    str = va_arg(va, char *);
+    print_out("", str);
+    break;
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    /* ChannelUserMode Change*/
+    DEBUG("Notify: CUMODE CHANGE");
+    id = va_arg(va, int);
+    sender = va_arg(va, void *);
+    mode = va_arg(va, SilcUInt32);
+    sender2 = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    str = get_scc_name_by_id(id, sender);
+    str2 = silc_client_chumode(mode);
+    print_out(channel->channel_name, "-!- channel user mode/%s/%s [%s] by %s", 
+              channel->channel_name, sender2->nickname, str2 ? 
+              str2 : "removed all", str ? str : "");
+    silc_free(str);
+    silc_free(str2);
+    break;
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    DEBUG("Notify:  CMODE CHANGE");
+    id = va_arg(va, int);
+    sender = va_arg(va, void *);
+    mode = va_arg(va, SilcUInt32);
+    (void)va_arg(va, char *);                  /* cipher */
+    (void)va_arg(va, char *);                  /* hmac */
+    (void)va_arg(va, char *);                  /* passphrase */
+    (void)va_arg(va, SilcPublicKey);           /* founder key */
+    (void)va_arg(va, SilcDList);
+    channel = va_arg(va, SilcChannelEntry);
+
+    str = get_scc_name_by_id(id, sender);
+    str2 = silc_client_chmode(mode, channel->cipher, channel->hmac);
+    print_out(channel->channel_name, "-!- channel mode/%s [%s] by %s",
+              channel->channel_name, str2 ? str2 : "removed all", 
+              str ? str : "");
+    silc_free(str);
+    silc_free(str2);
+    break;
+  case SILC_NOTIFY_TYPE_KICKED:
+    DEBUG("Notify: KICKED");
+    sender = va_arg(va, SilcClientEntry);
+    str = va_arg(va, char *);
+    sender2 = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    if (sender == silc_client->conn->local_entry) {
+      /* The User was kicked */
+      print_out(channel->channel_name, "-!- You were kicked by %s [%s]", 
+                sender2->nickname ? sender2->nickname : "anonymous",
+                str ? str : "");
+      for (c = channels; c; c = c->next)
+	if (!strcmp(c->silc->channel_name, channel->channel_name))
+	  rm_channel(c);
+    }
+    else {
+      print_out(channel->channel_name, "-!- %s was kicked by %s [%s]", 
+                sender->nickname, sender2->nickname ? sender2->nickname 
+                : "anonymous", str ? str : "");
+    }
+    break;
+  case SILC_NOTIFY_TYPE_KILLED:
+    DEBUG("Notify: KILLED");
+    sender = va_arg(va, SilcClientEntry);
+    rm_buddy(sender);
+    refresh_buddylist();
+    str = va_arg(va, char *);
+    id = va_arg(va, int);
+    sender2 = va_arg(va, void *);
+    str2 = get_scc_name_by_id(id, sender2);
+    if (sender == silc_client->conn->local_entry) {
+      /* The User was killed */
+      for (c = channels; c; c = c->next)
+	print_out(c->silc->channel_name, "-!- You were killed from the Silc "
+                  "Network by %s [%s]", str2 ? str2 : "anonymous", str);
+      for (q = queries; q; q = q->next){
+	char *path;
+	silc_asprintf(&path, "query/%s", sender->nickname);
+	print_out(path, "-!- You were killed from the Silc Network by %s [%s]",
+                  str2 ? str2 : "anonymous", str);
+	silc_free(path);
+      }
+      exit(0);
+    }
+    else {
+      silc_hash_table_list(sender->channels, &ch);
+      while (silc_hash_table_get(&ch, (void *)&channel, (void *)&channel2)) {
+	for(c = channels; c; c = c->next)
+	  if(!strcmp(c->silc->channel_name, channel->channel_name))
+	    print_out(channel->channel_name, "-!- %s was killed from the "
+                      "Silc Network by %s [%s]", sender->nickname, 
+                      str2 ? str2 : "anonymous", str);
+
+      }
+      silc_hash_table_list_reset(&ch);
+
+      for (q = queries; q; q = q->next)
+	if(SILC_ID_CLIENT_COMPARE(&sender->id, &q->silc->id)){
+	  char *path;
+	  silc_asprintf(&path, "query/%s", sender->nickname);
+	  print_out(path,  "-!- %s was killed from the Silc Network by %s [%s]",
+                    sender->nickname, str2 ? str2 : "anonymous", str);
+	  silc_free(path);
+	}
+    }
+  case SILC_NOTIFY_TYPE_WATCH:
+    DEBUG("Notify: WATCH");
+    sender = va_arg(va, SilcClientEntry);
+    str = va_arg(va, char *);
+    mode = va_arg(va, SilcUInt32);
+    SilcNotifyType watch_type=va_arg(va, int);
+    if (watch_type == SILC_NOTIFY_TYPE_NICK_CHANGE){
+      add_buddy(sender);
+      if (str)
+	print_out("", "-!- Watch: %s is known as %s", sender->nickname, str);
+      else
+	print_out("", "-!- Watch: %s is online now", sender->nickname, str);
+
+      va_end(va);
+      refresh_buddylist();
+      return;
+    }
+    proc_watch(sender, mode, watch_type);
+    break;
+  default:
+    printf("TYPE: %d\n", type);
+    /* Ignore rest */
+    break;
+  }
+
+  va_end(va);
+}
+
+/* }}} */
+/* {{{ silc_private_message */
+
+static void
+silc_private_message(SilcClient client, SilcClientConnection conn,
+		     SilcClientEntry sender, SilcMessagePayload payload,
+		     SilcMessageFlags flags,
+		     const unsigned char *msg,
+		     SilcUInt32 message_len)
+{
+
+  Query *q;
+  char *path = NULL;
+  char *sigstat = NULL;
+  for (q=queries; q; q=q->next)
+    if (SILC_ID_CLIENT_COMPARE(&sender->id, &q->silc->id)){
+      /* We have an open query */
+      silc_asprintf(&path, "query/%s", sender->nickname);
+      break;
+    }
+  if(flags & SILC_MESSAGE_FLAG_SIGNED)
+    sigstat=silc_verify_message(sender, payload);
+
+  if (flags & SILC_MESSAGE_FLAG_DATA) {
+    /* Process MIME message */
+    SilcMime mime = silc_mime_decode(NULL, msg, message_len);
+    si_process_mime(client, conn, sender, NULL, payload, NULL, flags,
+		    mime, FALSE);
+    free(path);
+    return;
+  }
+
+  print_out(path ? path : "",  "%s<%s> %s", sigstat ? sigstat : "",
+            sender->nickname, (char *)msg);
+  free(path);
+}
+
+/* }}} */
+/* {{{ verify_public_key */
+int 
+verify_public_key(SilcPublicKey key, int remote) 
+{
+  unsigned char *pk;
+  SilcUInt32 pk_len;
+  char *fp, *path;
+  unsigned int tmp;
+  DIR *dir;
+  struct dirent *entry;
+  pk = silc_pkcs_public_key_encode(key, &pk_len);
+  fp = silc_hash_fingerprint(NULL, pk, pk_len);
+  for (tmp = 0; tmp < strlen(fp); tmp++)
+    if(fp[tmp] == ' ')
+      fp[tmp]='_';
+  silc_asprintf(&path, "%s/.silc/%s", (char *)getenv("HOME"), 
+                remote == SERVER ? "serverkeys" : "clientkeys");
+  create_dirtree(path);
+  dir = opendir(path);
+  silc_free(path);
+
+  while((entry = readdir(dir))) {
+    if(!strncmp(entry->d_name, fp, strlen(fp))){
+      silc_asprintf(&path, "%s/.silc/%s/%s", (char *)getenv("HOME"), 
+                    remote == SERVER ? "serverkeys" : "clientkeys", 
+                    entry->d_name);
+      /* Load key */
+      SilcPublicKey cached_pk = NULL;
+      if (!silc_pkcs_load_public_key(path, &cached_pk)) {
+	fprintf(stderr, "Couldn't load file: %s\n", path);
+	return KEY_UNKOWN;
+	break;
+      }
+      if(silc_pkcs_public_key_compare(key, cached_pk)){
+	silc_free(path);
+	silc_free(fp);
+	return KEY_TRUSTED;
+      }
+      else {
+	silc_free(path);
+	silc_free(fp);
+	return KEY_INVALID;
+      }
+    }
+  }
+  closedir(dir);
+  silc_free(fp);
+  return KEY_UNKOWN;
+}
+/* }}} */
+/* {{{ silc_verify_public_key */
+static void
+silc_verify_public_key(SilcClient client, SilcClientConnection conn,
+		       SilcConnectionType conn_type, 
+                       SilcPublicKey pkey, 
+		       SilcVerifyPublicKey completion, void *context)
+{
+  char *fingerprint, *path, *pos; 
+  unsigned char *pk;
+  unsigned int tmp;
+  SilcUInt32 pk_len;
+
+  pk = silc_pkcs_public_key_encode(pkey, &pk_len);
+  fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+
+  for (tmp = 0; tmp < strlen(fingerprint); tmp++)
+    if(fingerprint[tmp]==' ')
+      fingerprint[tmp]='_';
+
+  if (conn_type == SILC_CONN_SERVER || conn_type == SILC_CONN_ROUTER){
+    int res = verify_public_key(pkey, SERVER);
+      if (res == KEY_TRUSTED){
+	DEBUG("Verify: TRUSTED");
+	completion(TRUE, context);
+        silc_free(pk);
+	return;
+      }
+      else if ( res == KEY_INVALID ){
+	print_out("", "-!- Error: The cached public key is not the same as the sent one!");
+	printf("ERROR: INVALID KEY; PANIC\n");
+	exit(1);
+      }
+      else {
+	/* Save the Public Key */
+	silc_asprintf(&path, "%s/.silc/incoming_keys/%s(%s):server",
+                      getenv("HOME"), fingerprint, conn->remote_host);
+	pos = strrchr(path, '/');
+	pos[0] = 0;
+	create_dirtree(path);
+	pos[0] = '/';
+	if(!silc_pkcs_save_public_key(path, pkey, SILC_PKCS_FILE_BASE64)){
+	  fprintf(stderr, "Couldn't save Public Key\n");
+	  exit(1);
+	}
+	printf("The server's public key you wanted to connect is unkown!\n");
+	printf("Name: %s\n", silc_pkcs_get_name(pkey));
+	printf("Host: %s; Port: %d\n", conn->remote_host, conn->remote_port);
+	printf("si has saved his public key to:\n");
+	printf("%s\n", path);
+	printf("\nIf you trust this key move it to ~/.silc/serverkeys, but don't rename it\n");
+	exit(1);
+      }
+  }
+  else {
+    /* Clients */
+    int res = verify_public_key(pkey, CLIENT);
+    if (res == KEY_TRUSTED){
+      DEBUG("Verify: TRUSTED");
+      completion(TRUE, context);
+    }
+    else if (res == KEY_INVALID) {
+      print_out("", "-!- Error: It seems as if the saved key (%s) is poisoned", fingerprint);
+      completion(FALSE, context);
+    }
+    else {
+      print_out("", "-!- Error: You had to trust the key first (%s)", fingerprint);
+      completion(FALSE, context);
+    }
+    silc_free(pk);
+  }
+}
+/* }}} */
+/* {{{ silc_ftp */
+static void
+silc_ftp(SilcClient client, SilcClientConnection conn,
+	 SilcClientEntry client_entry, SilcUInt32 session_id,
+	 const char *hostname, SilcUInt16 port)
+{
+  DEBUG("Ftp: REQUEST");
+  add_transfer(transfer_count, session_id, client_entry, FILE_TYPE_IN);
+  if(hostname && port)
+    print_out("","-!- %s would like to send you a file (Number %d) [%s:%d]", client_entry->nickname, transfer_count, hostname, port);
+  else
+    print_out("","-!- %s would like to send you a file (Number %d)", client_entry->nickname, transfer_count);
+  transfer_count++;
+}
+/* }}} */
+
+/* {{{ Empty and unused, but required Functions */
+static void
+silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+		     char *hostname, SilcUInt16 port,
+                     SilcAuthMethod method,
+		     SilcGetAuthMeth completion,
+		     void *context)
+{
+  /* MyBot assumes that there is no authentication requirement in the
+     server and sends nothing as authentication.  We just reply with
+     TRUE, meaning we know what is the authentication method. :). */
+  completion(SILC_AUTH_NONE, NULL, 0, context);
+}
+
+static void
+silc_say(SilcClient client, SilcClientConnection conn,
+	 SilcClientMessageType type, char *msg, ...)
+{
+  va_list va;
+  va_start(va, msg);
+  char *message;
+  silc_vasprintf(&message, msg, va);
+  print_out("", "-!- %s", message);
+  silc_free(message);
+}
+
+static void
+silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
+		    SilcAskPassphrase completion, void *context)
+{
+  completion(NULL, 0, context);
+}
+
+void
+silc_key_agreement(SilcClient client, SilcClientConnection conn,
+		   SilcClientEntry client_entry, const char *hostname,
+		   SilcUInt16 protocol, SilcUInt16 port)
+{
+}
+/* }}} */
+
+/* {{{ Client-Ops and main() */
+SilcClientOperations ops = {
+  silc_say,
+  silc_channel_message,
+  silc_private_message,
+  silc_notify,
+  silc_command,
+  silc_command_reply,
+  silc_get_auth_method,
+  silc_verify_public_key,
+  silc_ask_passphrase,
+  silc_key_agreement,
+  silc_ftp,
+};
+
+int main(int argc, char **argv)
+{
+  char c;
+  int do_fork = 0;
+
+  while (1) {
+    int option_index = 0;
+    static struct option long_options[] = {
+      {"version", 0, 0, 'v'},
+      {"help", 0, 0, 'h'},
+      {"silc-dir", 1, 0, 'i'},
+      {"server", 1, 0, 's'},
+      {"port", 1, 0, 'p'},
+      {"nick", 1, 0, 'n'},
+      {"fullname", 1, 0, 'f'},
+      {"init-script", 1, 0, 'x'},
+      {"debug", 0, 0, 'd'},
+      {"fork", 0, 0, 'F'}, 
+      {0, 0, 0, 0}
+    };
+
+    c = getopt_long (argc, argv, "dFx:i:s:p:n:f:vh",
+		     long_options, &option_index);
+    if (c == -1)
+      break;
+
+    switch (c) {
+    case 'v': version(); break;
+    case 'h': usage(); break;
+    case 'i': prefix=strdup(optarg); break;
+    case 's': host = strdup(optarg); break;
+    case 'p': port = atoi(optarg); break;
+    case 'n': username = strdup(optarg); break;
+    case 'f': realname = strdup(optarg); break;
+    case 'x': init_script = strdup(optarg); break;
+    case 'F': do_fork = 1; break;
+    case 'd': debug = 1; break;
+    default: usage(); break;
+    }
+  }
+
+  if(!strlen(prefix)){
+    prefix=malloc(strlen(getenv("HOME"))+5);
+    NULL_TEST_ARG(prefix,1);
+    sprintf(prefix, "%s/irc", getenv("HOME"));
+  }
+
+  if (!username)
+    username = silc_get_username();
+
+  if(do_fork) {
+    pid_t p = fork();
+
+    if(p < 0) {
+      /* fork failed */
+      perror("si");
+      return 1;
+    }
+
+    if(p) {
+      /* parent process */
+      return 0;
+    }
+
+    /* child process, we're a daemon, therefore close terminal fds */
+    close(0);
+    close(1);
+    close(2);
+  }
+
+  /* Run the Mainloop */
+  return run();
+}
+
+/* }}} */




More information about the Pkg-silc-commits mailing list