[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(¶ms, 0, sizeof(params));
+ params.local_ip = silc_localip();
+ params.no_authentication = TRUE;
+
+ int res = silc_client_file_receive(silc_client->client, silc_client->conn,
+ ¶ms, 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(¶ms, 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, ¶ms, 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(¶ms, 0, sizeof(params));
+ strcat(params.nickname_format, "%n@%h%a");
+
+
+ silc_client->client = silc_client_alloc(&ops, ¶ms, 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