- build fix for poor distros who have a hard time with libircclient (now we just include this small lib in the source tree) so no longer required as an external lib

This commit is contained in:
Mark Vejvoda
2010-12-27 09:01:40 +00:00
parent b76cc89b60
commit 8d8afe78b5
873 changed files with 99837 additions and 95 deletions

View File

@@ -0,0 +1,39 @@
# $Id: Makefile.in 84 2009-01-10 01:37:29Z chromerium $
CC = @CC@
CFLAGS = -Wall -DIN_BUILDING_LIBIRC @CFLAGS@
AR=@AR@ cr
RANLIB=@RANLIB@
INCLUDES=-I../include
DESTDIR=
OBJS = libircclient.o
all: lib
lib: libircclient.a
install: lib
-mkdir -p $(DESTDIR)@prefix@/include
-mkdir -p $(DESTDIR)@prefix@/lib
cp ../include/libircclient.h $(DESTDIR)@prefix@/include/libircclient.h
cp ../include/libirc_errors.h $(DESTDIR)@prefix@/include/libirc_errors.h
cp ../include/libirc_events.h $(DESTDIR)@prefix@/include/libirc_events.h
cp libircclient.a $(DESTDIR)@prefix@/lib/libircclient.a
cd $(DESTDIR)@prefix@/lib && ln -s libircclient.a libirc.a
$(OBJS): utils.c dcc.c errors.c portable.c sockets.c colors.c
libircclient.a: $(OBJS)
$(AR) libircclient.a $(OBJS)
$(RANLIB) libircclient.a
clean:
rm -f libircclient.a $(OBJS)
distclean: clean
-rm -f Makefile
.c.o:
@echo "Compiling $<"
@$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

View File

@@ -0,0 +1,390 @@
/*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#include <ctype.h>
#define LIBIRC_COLORPARSER_BOLD (1<<1)
#define LIBIRC_COLORPARSER_UNDERLINE (1<<2)
#define LIBIRC_COLORPARSER_REVERSE (1<<3)
#define LIBIRC_COLORPARSER_COLOR (1<<4)
#define LIBIRC_COLORPARSER_MAXCOLORS 15
static const char * color_replacement_table[] =
{
"WHITE",
"BLACK",
"DARKBLUE",
"DARKGREEN",
"RED",
"BROWN",
"PURPLE",
"OLIVE",
"YELLOW",
"GREEN",
"TEAL",
"CYAN",
"BLUE",
"MAGENTA",
"DARKGRAY",
"LIGHTGRAY",
0
};
static inline void libirc_colorparser_addorcat (char ** destline, unsigned int * destlen, const char * str)
{
unsigned int len = strlen(str);
if ( *destline )
{
strcpy (*destline, str);
*destline += len;
}
else
*destlen += len;
}
static void libirc_colorparser_applymask (unsigned int * mask,
char ** destline, unsigned int * destlen,
unsigned int bitmask, const char * start, const char * end)
{
if ( (*mask & bitmask) != 0 )
{
*mask &= ~bitmask;
libirc_colorparser_addorcat (destline, destlen, end);
}
else
{
*mask |= bitmask;
libirc_colorparser_addorcat (destline, destlen, start);
}
}
static void libirc_colorparser_applycolor (unsigned int * mask,
char ** destline, unsigned int * destlen,
unsigned int colorid, unsigned int bgcolorid)
{
const char * end = "[/COLOR]";
char startbuf[64];
if ( bgcolorid != 0 )
sprintf (startbuf, "[COLOR=%s/%s]", color_replacement_table[colorid], color_replacement_table[bgcolorid]);
else
sprintf (startbuf, "[COLOR=%s]", color_replacement_table[colorid]);
if ( (*mask & LIBIRC_COLORPARSER_COLOR) != 0 )
libirc_colorparser_addorcat (destline, destlen, end);
*mask |= LIBIRC_COLORPARSER_COLOR;
libirc_colorparser_addorcat (destline, destlen, startbuf);
}
static void libirc_colorparser_closetags (unsigned int * mask,
char ** destline, unsigned int * destlen)
{
if ( *mask & LIBIRC_COLORPARSER_BOLD )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_BOLD, 0, "[/B]");
if ( *mask & LIBIRC_COLORPARSER_UNDERLINE )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_UNDERLINE, 0, "[/U]");
if ( *mask & LIBIRC_COLORPARSER_REVERSE )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_REVERSE, 0, "[/I]");
if ( *mask & LIBIRC_COLORPARSER_COLOR )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_COLOR, 0, "[/COLOR]");
}
/*
* IRC to [code] color conversion. Or strip.
*/
static char * libirc_colorparser_irc2code (const char * source, int strip)
{
unsigned int mask = 0, destlen = 0;
char * destline = 0, *d = 0;
const char *p;
int current_color = 1, current_bg = 0;
/*
* There will be two passes. First pass calculates the total length of
* the destination string. The second pass allocates memory for the string,
* and fills it.
*/
while ( destline == 0 ) // destline will be set after the 2nd pass
{
if ( destlen > 0 )
{
// This is the 2nd pass; allocate memory.
if ( (destline = malloc (destlen)) == 0 )
return 0;
d = destline;
}
for ( p = source; *p; p++ )
{
switch (*p)
{
case 0x02: // bold
if ( strip )
continue;
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_BOLD, "[B]", "[/B]");
break;
case 0x1F: // underline
if ( strip )
continue;
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_UNDERLINE, "[U]", "[/U]");
break;
case 0x16: // reverse
if ( strip )
continue;
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_REVERSE, "[I]", "[/I]");
break;
case 0x0F: // reset colors
if ( strip )
continue;
libirc_colorparser_closetags (&mask, &d, &destlen);
break;
case 0x03: // set color
if ( isdigit (p[1]) )
{
// Parse
int bgcolor = -1, color = p[1] - 0x30;
p++;
if ( isdigit (p[1]) )
{
color = color * 10 + (p[1] - 0x30);
p++;
}
// If there is a comma, search for the following
// background color
if ( p[1] == ',' && isdigit (p[2]) )
{
bgcolor = p[2] - 0x30;
p += 2;
if ( isdigit (p[1]) )
{
bgcolor = bgcolor * 10 + (p[1] - 0x30);
p++;
}
}
// Check for range
if ( color <= LIBIRC_COLORPARSER_MAXCOLORS
&& bgcolor <= LIBIRC_COLORPARSER_MAXCOLORS )
{
if ( strip )
continue;
current_color = color;
if ( bgcolor != -1 )
current_bg = bgcolor;
libirc_colorparser_applycolor (&mask, &d, &destlen, color, current_bg);
}
}
break;
default:
if ( destline )
*d++ = *p;
else
destlen++;
break;
}
}
// Close all the opened tags
libirc_colorparser_closetags (&mask, &d, &destlen);
destlen++; // for 0-terminator
}
*d = '\0';
return destline;
}
static int libirc_colorparser_colorlookup (const char * color)
{
int i;
for ( i = 0; color_replacement_table[i]; i++ )
if ( !strcmp (color, color_replacement_table[i]) )
return i;
return -1;
}
/*
* [code] to IRC color conversion.
*/
char * irc_color_convert_to_mirc (const char * source)
{
unsigned int destlen = 0;
char * destline = 0, *d = 0;
const char *p1, *p2, *cur;
/*
* There will be two passes. First pass calculates the total length of
* the destination string. The second pass allocates memory for the string,
* and fills it.
*/
while ( destline == 0 ) // destline will be set after the 2nd pass
{
if ( destlen > 0 )
{
// This is the 2nd pass; allocate memory.
if ( (destline = malloc (destlen)) == 0 )
return 0;
d = destline;
}
cur = source;
while ( (p1 = strchr (cur, '[')) != 0 )
{
const char * replacedval = 0;
p2 = 0;
// Check if the closing bracket is available after p1
// and the tag length is suitable
if ( p1[1] != '\0'
&& (p2 = strchr (p1, ']')) != 0
&& (p2 - p1) > 1
&& (p2 - p1) < 31 )
{
// Get the tag
char tagbuf[32];
int taglen = p2 - p1 - 1;
memcpy (tagbuf, p1 + 1, taglen);
tagbuf[taglen] = '\0';
if ( !strcmp (tagbuf, "/COLOR") )
replacedval = "\x0F";
else if ( strstr (tagbuf, "COLOR=") == tagbuf )
{
int color, bgcolor = -2;
char * bcol;
bcol = strchr (tagbuf + 6, '/');
if ( bcol )
{
*bcol++ = '\0';
bgcolor = libirc_colorparser_colorlookup (bcol);
}
color = libirc_colorparser_colorlookup (tagbuf + 6);
if ( color != -1 && bgcolor == -2 )
{
sprintf (tagbuf, "\x03%02d", color);
replacedval = tagbuf;
}
else if ( color != -1 && bgcolor >= 0 )
{
sprintf (tagbuf, "\x03%02d,%02d", color, bgcolor);
replacedval = tagbuf;
}
}
else if ( !strcmp (tagbuf, "B") || !strcmp (tagbuf, "/B") )
replacedval = "\x02";
else if ( !strcmp (tagbuf, "U") || !strcmp (tagbuf, "/U") )
replacedval = "\x1F";
else if ( !strcmp (tagbuf, "I") || !strcmp (tagbuf, "/I") )
replacedval = "\x16";
}
if ( replacedval )
{
// add a part before the tag
int partlen = p1 - cur;
if ( destline )
{
memcpy (d, cur, partlen);
d += partlen;
}
else
destlen += partlen;
// Add the replacement
libirc_colorparser_addorcat (&d, &destlen, replacedval);
// And move the pointer
cur = p2 + 1;
}
else
{
// add a whole part before the end tag
int partlen;
if ( !p2 )
p2 = cur + strlen(cur);
partlen = p2 - cur + 1;
if ( destline )
{
memcpy (d, cur, partlen);
d += partlen;
}
else
destlen += partlen;
// And move the pointer
cur = p2 + 1;
}
}
// Add the rest of string
libirc_colorparser_addorcat (&d, &destlen, cur);
destlen++; // for 0-terminator
}
*d = '\0';
return destline;
}
char * irc_color_strip_from_mirc (const char * message)
{
return libirc_colorparser_irc2code (message, 1);
}
char * irc_color_convert_from_mirc (const char * message)
{
return libirc_colorparser_irc2code (message, 0);
}

View File

@@ -0,0 +1,869 @@
/*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#define LIBIRC_DCC_CHAT 1
#define LIBIRC_DCC_SENDFILE 2
#define LIBIRC_DCC_RECVFILE 3
#include "libircclient.h"
static irc_dcc_session_t * libirc_find_dcc_session (irc_session_t * session, irc_dcc_t dccid, int lock_list)
{
irc_dcc_session_t * s, *found = 0;
if ( lock_list )
libirc_mutex_lock (&session->mutex_dcc);
for ( s = session->dcc_sessions; s; s = s->next )
{
if ( s->id == dccid )
{
found = s;
break;
}
}
if ( found == 0 && lock_list )
libirc_mutex_unlock (&session->mutex_dcc);
return found;
}
static void libirc_dcc_destroy_nolock (irc_session_t * session, irc_dcc_t dccid)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 0);
if ( dcc )
{
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
dcc->state = LIBIRC_STATE_REMOVED;
}
}
static void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list)
{
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
if ( dcc->dccsend_file_fp )
fclose (dcc->dccsend_file_fp);
dcc->dccsend_file_fp = 0;
libirc_mutex_destroy (&dcc->mutex_outbuf);
if ( lock_list )
libirc_mutex_lock (&session->mutex_dcc);
if ( session->dcc_sessions != dcc )
{
irc_dcc_session_t * s;
for ( s = session->dcc_sessions; s; s = s->next )
{
if ( s->next == dcc )
{
s->next = dcc->next;
break;
}
}
}
else
session->dcc_sessions = dcc->next;
if ( lock_list )
libirc_mutex_unlock (&session->mutex_dcc);
free (dcc);
}
static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd)
{
irc_dcc_session_t * dcc, *dcc_next;
time_t now = time (0);
libirc_mutex_lock (&ircsession->mutex_dcc);
// Preprocessing DCC list:
// - ask DCC send callbacks for data;
// - remove unused DCC structures
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc_next )
{
dcc_next = dcc->next;
// Remove timed-out sessions
if ( (dcc->state == LIBIRC_STATE_CONNECTING
|| dcc->state == LIBIRC_STATE_INIT
|| dcc->state == LIBIRC_STATE_LISTENING)
&& now - dcc->timeout > ircsession->dcc_timeout )
{
// Inform the caller about DCC timeout.
// Do not inform when state is LIBIRC_STATE_INIT - session
// was initiated from someone else, and callbacks aren't set yet.
if ( dcc->state != LIBIRC_STATE_INIT )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
if ( dcc->cb )
(*dcc->cb)(ircsession, dcc->id, LIBIRC_ERR_TIMEOUT, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
}
libirc_remove_dcc_session (ircsession, dcc, 0);
}
/*
* If we're sending file, and the output buffer is empty, we need
* to provide some data.
*/
if ( dcc->state == LIBIRC_STATE_CONNECTED
&& dcc->dccmode == LIBIRC_DCC_SENDFILE
&& dcc->dccsend_file_fp
&& dcc->outgoing_offset == 0 )
{
int len = fread (dcc->outgoing_buf, 1, sizeof (dcc->outgoing_buf), dcc->dccsend_file_fp);
if ( len <= 0 )
{
int err = (len < 0 ? LIBIRC_ERR_READ : 0);
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
else
dcc->outgoing_offset = len;
}
// Clean up unused sessions
if ( dcc->state == LIBIRC_STATE_REMOVED )
libirc_remove_dcc_session (ircsession, dcc, 0);
}
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
{
switch (dcc->state)
{
case LIBIRC_STATE_LISTENING:
// While listening, only in_set descriptor should be set
libirc_add_to_set (dcc->sock, in_set, maxfd);
break;
case LIBIRC_STATE_CONNECTING:
// While connection, only out_set descriptor should be set
libirc_add_to_set (dcc->sock, out_set, maxfd);
break;
case LIBIRC_STATE_CONNECTED:
// Add input descriptor if there is space in input buffer
// and it is DCC chat (during DCC send, there is nothing to recv)
if ( dcc->incoming_offset < sizeof(dcc->incoming_buf) - 1 )
libirc_add_to_set (dcc->sock, in_set, maxfd);
// Add output descriptor if there is something in output buffer
libirc_mutex_lock (&dcc->mutex_outbuf);
if ( dcc->outgoing_offset > 0 )
libirc_add_to_set (dcc->sock, out_set, maxfd);
libirc_mutex_unlock (&dcc->mutex_outbuf);
break;
case LIBIRC_STATE_CONFIRM_SIZE:
/*
* If we're receiving file, then WE should confirm the transferred
* part (so we have to sent data). But if we're sending the file,
* then RECEIVER should confirm the packet, so we have to receive
* data.
*
* We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers
* can't change asynchronously.
*/
if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 )
libirc_add_to_set (dcc->sock, out_set, maxfd);
if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 )
libirc_add_to_set (dcc->sock, in_set, maxfd);
}
}
libirc_mutex_unlock (&ircsession->mutex_dcc);
}
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
{
irc_dcc_session_t * dcc;
/*
* We need to use such a complex scheme here, because on every callback
* a number of DCC sessions could be destroyed.
*/
libirc_mutex_lock (&ircsession->mutex_dcc);
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
{
if ( dcc->state == LIBIRC_STATE_LISTENING
&& FD_ISSET (dcc->sock, in_set) )
{
socklen_t len = sizeof(dcc->remote_addr);
int nsock, err = 0;
// New connection is available; accept it.
if ( socket_accept (&dcc->sock, &nsock, (struct sockaddr *) &dcc->remote_addr, &len) )
err = LIBIRC_ERR_ACCEPT;
// On success, change the active socket and change the state
if ( err == 0 )
{
// close the listen socket, and replace it by a newly
// accepted
socket_close (&dcc->sock);
dcc->sock = nsock;
dcc->state = LIBIRC_STATE_CONNECTED;
}
// If this is DCC chat, inform the caller about accept()
// success or failure.
// Otherwise (DCC send) there is no reason.
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
}
if ( err )
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
if ( dcc->state == LIBIRC_STATE_CONNECTING
&& FD_ISSET (dcc->sock, out_set) )
{
// Now we have to determine whether the socket is connected
// or the connect is failed
struct sockaddr_in saddr;
socklen_t slen = sizeof(saddr);
int err = 0;
if ( getpeername (dcc->sock, (struct sockaddr*)&saddr, &slen) < 0 )
err = LIBIRC_ERR_CONNECT;
// On success, change the state
if ( err == 0 )
dcc->state = LIBIRC_STATE_CONNECTED;
// If this is DCC chat, inform the caller about connect()
// success or failure.
// Otherwise (DCC send) there is no reason.
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
}
if ( err )
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
if ( dcc->state == LIBIRC_STATE_CONNECTED
|| dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
{
if ( FD_ISSET (dcc->sock, in_set) )
{
int length, offset = 0, err = 0;
unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;
length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);
if ( length < 0 )
{
err = LIBIRC_ERR_READ;
}
else if ( length == 0 )
{
err = LIBIRC_ERR_CLOSED;
if ( dcc->dccsend_file_fp )
{
fclose (dcc->dccsend_file_fp);
dcc->dccsend_file_fp = 0;
}
}
else
{
dcc->incoming_offset += length;
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
offset = dcc->incoming_offset;
else
offset = libirc_findcrorlf (dcc->incoming_buf, dcc->incoming_offset);
/*
* In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
* callbacks (except there is an error). We just receive
* the data, and compare it with the amount sent.
*/
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
{
if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
abort();
if ( dcc->incoming_offset == 4 )
{
unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));
// Sent size confirmed
if ( dcc->file_confirm_offset == received_size )
{
dcc->state = LIBIRC_STATE_CONNECTED;
dcc->incoming_offset = 0;
}
else
err = LIBIRC_ERR_WRITE;
}
}
else
{
/*
* If it is DCC_CHAT, we send a 0-terminated string
* (which is smaller than offset). Otherwise we send
* a full buffer.
*/
libirc_mutex_unlock (&ircsession->mutex_dcc);
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
{
if ( dcc->dccmode != LIBIRC_DCC_RECVFILE )
abort();
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);
/*
* If the session is not terminated in callback,
* put the sent amount into the sent_packet_size_net_byteorder
*/
if ( dcc->state != LIBIRC_STATE_REMOVED )
{
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
dcc->file_confirm_offset += offset;
*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);
dcc->outgoing_offset = 4;
}
}
else
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, strlen(dcc->incoming_buf));
libirc_mutex_lock (&ircsession->mutex_dcc);
if ( dcc->incoming_offset - offset > 0 )
memmove (dcc->incoming_buf, dcc->incoming_buf + offset, dcc->incoming_offset - offset);
dcc->incoming_offset -= offset;
}
}
/*
* If error arises somewhere above, we inform the caller
* of failure, and destroy this session.
*/
if ( err )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
}
/*
* Session might be closed (with sock = -1) after the in_set
* processing, so before out_set processing we should check
* for this case
*/
if ( dcc->state == LIBIRC_STATE_REMOVED )
continue;
/*
* Write bit set - we can send() something, and it won't block.
*/
if ( FD_ISSET (dcc->sock, out_set) )
{
int length, offset, err = 0;
/*
* Because in some cases outgoing_buf could be changed
* asynchronously (by another thread), we should lock
* it.
*/
libirc_mutex_lock (&dcc->mutex_outbuf);
offset = dcc->outgoing_offset;
if ( offset > 0 )
{
length = socket_send (&dcc->sock, dcc->outgoing_buf, offset);
if ( length < 0 )
err = LIBIRC_ERR_WRITE;
else if ( length == 0 )
err = LIBIRC_ERR_CLOSED;
else
{
/*
* If this was DCC_SENDFILE, and we just sent a packet,
* change the state to wait for confirmation (and store
* sent packet size)
*/
if ( dcc->state == LIBIRC_STATE_CONNECTED
&& dcc->dccmode == LIBIRC_DCC_SENDFILE )
{
dcc->file_confirm_offset += offset;
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
libirc_mutex_unlock (&ircsession->mutex_dcc);
libirc_mutex_unlock (&dcc->mutex_outbuf);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, offset);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_mutex_lock (&dcc->mutex_outbuf);
}
if ( dcc->outgoing_offset - length > 0 )
memmove (dcc->outgoing_buf, dcc->outgoing_buf + length, dcc->outgoing_offset - length);
dcc->outgoing_offset -= length;
/*
* If we just sent the confirmation data, change state
* back.
*/
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE
&& dcc->dccmode == LIBIRC_DCC_RECVFILE
&& dcc->outgoing_offset == 0 )
{
/*
* If the file is already received, we should inform
* the caller, and close the session.
*/
if ( dcc->received_file_size == dcc->file_confirm_offset )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
libirc_mutex_unlock (&dcc->mutex_outbuf);
(*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
else
{
/* Continue to receive the file */
dcc->state = LIBIRC_STATE_CONNECTED;
}
}
}
}
libirc_mutex_unlock (&dcc->mutex_outbuf);
/*
* If error arises somewhere above, we inform the caller
* of failure, and destroy this session.
*/
if ( err )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
}
}
}
libirc_mutex_unlock (&ircsession->mutex_dcc);
}
static int libirc_new_dcc_session (irc_session_t * session, unsigned long ip, unsigned short port, int dccmode, void * ctx, irc_dcc_session_t ** pdcc)
{
irc_dcc_session_t * dcc = malloc (sizeof(irc_dcc_session_t));
if ( !dcc )
return LIBIRC_ERR_NOMEM;
// setup
memset (dcc, 0, sizeof(irc_dcc_session_t));
dcc->dccsend_file_fp = 0;
if ( libirc_mutex_init (&dcc->mutex_outbuf) )
goto cleanup_exit_error;
if ( socket_create (PF_INET, SOCK_STREAM, &dcc->sock) )
goto cleanup_exit_error;
if ( !ip )
{
struct sockaddr_in saddr;
unsigned long arg = 1;
setsockopt (dcc->sock, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg));
memset (&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
memcpy (&saddr.sin_addr, &session->local_addr, sizeof(session->local_addr));
saddr.sin_port = htons (0);
if ( bind (dcc->sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0 )
goto cleanup_exit_error;
if ( listen (dcc->sock, 5) < 0 )
goto cleanup_exit_error;
dcc->state = LIBIRC_STATE_LISTENING;
}
else
{
// make socket non-blocking, so connect() call won't block
if ( socket_make_nonblocking (&dcc->sock) )
goto cleanup_exit_error;
memset (&dcc->remote_addr, 0, sizeof(dcc->remote_addr));
dcc->remote_addr.sin_family = AF_INET;
dcc->remote_addr.sin_addr.s_addr = htonl (ip); // what idiot came up with idea to send IP address in host-byteorder?
dcc->remote_addr.sin_port = htons(port);
dcc->state = LIBIRC_STATE_INIT;
}
dcc->dccmode = dccmode;
dcc->ctx = ctx;
time (&dcc->timeout);
// and store it
libirc_mutex_lock (&session->mutex_dcc);
dcc->id = session->dcc_last_id++;
dcc->next = session->dcc_sessions;
session->dcc_sessions = dcc;
libirc_mutex_unlock (&session->mutex_dcc);
*pdcc = dcc;
return 0;
cleanup_exit_error:
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
free (dcc);
return LIBIRC_ERR_SOCKET;
}
int irc_dcc_destroy (irc_session_t * session, irc_dcc_t dccid)
{
// This function doesn't actually destroy the session; it just changes
// its state to "removed" and closes the socket. The memory is actually
// freed after the processing loop.
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
dcc->state = LIBIRC_STATE_REMOVED;
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
int irc_dcc_chat (irc_session_t * session, void * ctx, const char * nick, irc_dcc_callback_t callback, irc_dcc_t * dccid)
{
struct sockaddr_in saddr;
socklen_t len = sizeof(saddr);
char cmdbuf[128], notbuf[128];
irc_dcc_session_t * dcc;
int err;
if ( session->state != LIBIRC_STATE_CONNECTED )
{
session->lasterror = LIBIRC_ERR_STATE;
return 1;
}
err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_CHAT, ctx, &dcc);
if ( err )
{
session->lasterror = err;
return 1;
}
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
{
session->lasterror = LIBIRC_ERR_SOCKET;
libirc_remove_dcc_session (session, dcc, 1);
return 1;
}
sprintf (notbuf, "DCC Chat (%s)", inet_ntoa (saddr.sin_addr));
sprintf (cmdbuf, "DCC CHAT chat %lu %u", (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port));
if ( irc_cmd_notice (session, nick, notbuf)
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
{
libirc_remove_dcc_session (session, dcc, 1);
return 1;
}
*dccid = dcc->id;
dcc->cb = callback;
dcc->dccmode = LIBIRC_DCC_CHAT;
return 0;
}
int irc_dcc_msg (irc_session_t * session, irc_dcc_t dccid, const char * text)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
{
session->lasterror = LIBIRC_ERR_INVAL;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
if ( (strlen(text) + 2) >= (sizeof(dcc->outgoing_buf) - dcc->outgoing_offset) )
{
session->lasterror = LIBIRC_ERR_NOMEM;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
libirc_mutex_lock (&dcc->mutex_outbuf);
strcpy (dcc->outgoing_buf + dcc->outgoing_offset, text);
dcc->outgoing_offset += strlen (text);
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0D;
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0A;
libirc_mutex_unlock (&dcc->mutex_outbuf);
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
static void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req)
{
char filenamebuf[256];
unsigned long ip, size;
unsigned short port;
if ( sscanf (req, "DCC CHAT chat %lu %hu", &ip, &port) == 2 )
{
if ( session->callbacks.event_dcc_chat_req )
{
irc_dcc_session_t * dcc;
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_CHAT, 0, &dcc);
if ( err )
{
session->lasterror = err;
return;
}
(*session->callbacks.event_dcc_chat_req) (session,
nick,
inet_ntoa (dcc->remote_addr.sin_addr),
dcc->id);
}
return;
}
else if ( sscanf (req, "DCC SEND %s %lu %hu %lu", filenamebuf, &ip, &port, &size) == 4 )
{
if ( session->callbacks.event_dcc_send_req )
{
irc_dcc_session_t * dcc;
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_RECVFILE, 0, &dcc);
if ( err )
{
session->lasterror = err;
return;
}
(*session->callbacks.event_dcc_send_req) (session,
nick,
inet_ntoa (dcc->remote_addr.sin_addr),
filenamebuf,
size,
dcc->id);
dcc->received_file_size = size;
}
return;
}
#if defined (ENABLE_DEBUG)
fprintf (stderr, "BUG: Unhandled DCC message: %s\n", req);
abort();
#endif
}
int irc_dcc_accept (irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dcc_callback_t callback)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->state != LIBIRC_STATE_INIT )
{
session->lasterror = LIBIRC_ERR_STATE;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
dcc->cb = callback;
dcc->ctx = ctx;
// Initiate the connect
if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) )
{
libirc_dcc_destroy_nolock (session, dccid);
libirc_mutex_unlock (&session->mutex_dcc);
session->lasterror = LIBIRC_ERR_CONNECT;
return 1;
}
dcc->state = LIBIRC_STATE_CONNECTING;
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
int irc_dcc_decline (irc_session_t * session, irc_dcc_t dccid)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->state != LIBIRC_STATE_INIT )
{
session->lasterror = LIBIRC_ERR_STATE;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
libirc_dcc_destroy_nolock (session, dccid);
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
int irc_dcc_sendfile (irc_session_t * session, void * ctx, const char * nick, const char * filename, irc_dcc_callback_t callback, irc_dcc_t * dccid)
{
struct sockaddr_in saddr;
socklen_t len = sizeof(saddr);
char cmdbuf[128], notbuf[128];
irc_dcc_session_t * dcc;
const char * p;
int err;
long filesize;
if ( !session || !dccid || !filename || !callback )
{
session->lasterror = LIBIRC_ERR_INVAL;
return 1;
}
if ( session->state != LIBIRC_STATE_CONNECTED )
{
session->lasterror = LIBIRC_ERR_STATE;
return 1;
}
if ( (err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_SENDFILE, ctx, &dcc)) != 0 )
{
session->lasterror = err;
return 1;
}
if ( (dcc->dccsend_file_fp = fopen (filename, "rb")) == 0 )
{
libirc_remove_dcc_session (session, dcc, 1);
session->lasterror = LIBIRC_ERR_OPENFILE;
return 1;
}
/* Get file length */
if ( fseek (dcc->dccsend_file_fp, 0, SEEK_END)
|| (filesize = ftell (dcc->dccsend_file_fp)) == -1
|| fseek (dcc->dccsend_file_fp, 0, SEEK_SET) )
{
libirc_remove_dcc_session (session, dcc, 1);
session->lasterror = LIBIRC_ERR_NODCCSEND;
return 1;
}
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
{
libirc_remove_dcc_session (session, dcc, 1);
session->lasterror = LIBIRC_ERR_SOCKET;
return 1;
}
// Remove path from the filename
if ( (p = strrchr (filename, '\\')) == 0
&& (p = strrchr (filename, '/')) == 0 )
p = filename;
else
p++; // skip directory slash
sprintf (notbuf, "DCC Send %s (%s)", p, inet_ntoa (saddr.sin_addr));
sprintf (cmdbuf, "DCC SEND %s %lu %u %ld", p, (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port), filesize);
if ( irc_cmd_notice (session, nick, notbuf)
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
{
libirc_remove_dcc_session (session, dcc, 1);
return 1;
}
*dccid = dcc->id;
dcc->cb = callback;
return 0;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#include "libircclient.h"
#include "libirc_session.h"
static const char * libirc_strerror[LIBIRC_ERR_MAX] =
{
"No error",
"Invalid argument",
"Host not resolved",
"Socket error",
"Could not connect",
"Remote connection closed",
"Out of memory",
"Could not accept new connection",
"Object not found",
"Could not DCC send this object",
"Read error",
"Write error",
"Illegal operation for this state",
"Timeout error",
"Could not open file",
"IRC session terminated",
"IPv6 not supported",
};
int irc_errno (irc_session_t * session)
{
return session->lasterror;
}
const char * irc_strerror (int ircerrno)
{
if ( ircerrno >= 0 && ircerrno < LIBIRC_ERR_MAX )
return libirc_strerror[ircerrno];
else
return "Invalid irc_errno value";
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
LIBRARY libircclient
EXPORTS
irc_create_session
irc_destroy_session
irc_connect
irc_connect6
irc_disconnect
irc_run
irc_add_select_descriptors
irc_process_select_descriptors
irc_send_raw
irc_cmd_quit
irc_cmd_join
irc_cmd_msg
irc_cmd_me
irc_cmd_notice
irc_cmd_kick
irc_cmd_ctcp_request
irc_cmd_ctcp_reply
irc_target_get_nick
irc_target_get_host
irc_dcc_chat
irc_dcc_msg
irc_dcc_accept
irc_dcc_decline
irc_dcc_sendfile
irc_dcc_destroy
irc_get_version
irc_set_ctx
irc_get_ctx
irc_errno
irc_strerror
irc_option_set
irc_option_reset
irc_is_connected
irc_cmd_part
irc_cmd_invite
irc_cmd_names
irc_cmd_list
irc_cmd_topic
irc_cmd_channel_mode
irc_cmd_user_mode
irc_cmd_nick
irc_cmd_whois
irc_color_strip_from_mirc
irc_color_convert_from_mirc
irc_color_convert_to_mirc

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#if !defined (WIN32)
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#if defined (ENABLE_THREADS)
#include <pthread.h>
typedef pthread_mutex_t port_mutex_t;
#if !defined (PTHREAD_MUTEX_RECURSIVE) && defined (PTHREAD_MUTEX_RECURSIVE_NP)
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
#endif
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#if defined (ENABLE_THREADS)
typedef CRITICAL_SECTION port_mutex_t;
#endif
#define inline
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#endif
#if defined (ENABLE_THREADS)
static inline int libirc_mutex_init (port_mutex_t * mutex)
{
#if defined (WIN32)
InitializeCriticalSection (mutex);
return 0;
#elif defined (PTHREAD_MUTEX_RECURSIVE)
pthread_mutexattr_t attr;
return (pthread_mutexattr_init (&attr)
|| pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)
|| pthread_mutex_init (mutex, &attr));
#else /* !defined (PTHREAD_MUTEX_RECURSIVE) */
return pthread_mutex_init (mutex, 0);
#endif /* defined (WIN32) */
}
static inline void libirc_mutex_destroy (port_mutex_t * mutex)
{
#if defined (WIN32)
DeleteCriticalSection (mutex);
#else
pthread_mutex_destroy (mutex);
#endif
}
static inline void libirc_mutex_lock (port_mutex_t * mutex)
{
#if defined (WIN32)
EnterCriticalSection (mutex);
#else
pthread_mutex_lock (mutex);
#endif
}
static inline void libirc_mutex_unlock (port_mutex_t * mutex)
{
#if defined (WIN32)
LeaveCriticalSection (mutex);
#else
pthread_mutex_unlock (mutex);
#endif
}
#else
typedef void * port_mutex_t;
static inline int libirc_mutex_init (port_mutex_t * mutex) { return 0; }
static inline void libirc_mutex_destroy (port_mutex_t * mutex) {}
static inline void libirc_mutex_lock (port_mutex_t * mutex) {}
static inline void libirc_mutex_unlock (port_mutex_t * mutex) {}
#endif
/*
* Stub for WIN32 dll to initialize winsock API
*/
#if defined (_USRDLL)
BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
WORD wVersionRequested = MAKEWORD (1, 1);
WSADATA wsaData;
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
if ( WSAStartup (wVersionRequested, &wsaData) != 0 )
return FALSE;
DisableThreadLibraryCalls (hinstDll);
break;
case DLL_PROCESS_DETACH:
WSACleanup();
break;
}
return TRUE;
}
#endif

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
/*
* The sockets interface was moved out to simplify going OpenSSL integration.
*/
#if !defined (WIN32)
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#define IS_SOCKET_ERROR(a) ((a)<0)
typedef int socket_t;
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define IS_SOCKET_ERROR(a) ((a)==SOCKET_ERROR)
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINPROGRESS WSAEINPROGRESS
#define EINTR WSAEINTR
typedef SOCKET socket_t;
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xFFFFFFFF
#endif
static int socket_error()
{
#if !defined (WIN32)
return errno;
#else
return WSAGetLastError();
#endif
}
static int socket_create (int domain, int type, socket_t * sock)
{
*sock = socket (domain, type, 0);
return IS_SOCKET_ERROR(*sock) ? 1 : 0;
}
static int socket_make_nonblocking (socket_t * sock)
{
#if !defined (WIN32)
return fcntl (*sock, F_SETFL, fcntl (*sock, F_GETFL,0 ) | O_NONBLOCK) != 0;
#else
unsigned long mode = 0;
return ioctlsocket (*sock, FIONBIO, &mode) == SOCKET_ERROR;
#endif
}
static int socket_close (socket_t * sock)
{
#if !defined (WIN32)
close (*sock);
#else
closesocket (*sock);
#endif
*sock = -1;
return 0;
}
static int socket_connect (socket_t * sock, const struct sockaddr *saddr, socklen_t len)
{
while ( 1 )
{
if ( connect (*sock, saddr, len) < 0 )
{
if ( socket_error() == EINTR )
continue;
if ( socket_error() != EINPROGRESS && socket_error() != EWOULDBLOCK )
return 1;
}
return 0;
}
}
static int socket_accept (socket_t * sock, socket_t * newsock, struct sockaddr *saddr, socklen_t * len)
{
while ( IS_SOCKET_ERROR(*newsock = accept (*sock, saddr, len)) )
{
if ( socket_error() == EINTR )
continue;
return 1;
}
return 0;
}
static int socket_recv (socket_t * sock, void * buf, size_t len)
{
int length;
while ( (length = recv (*sock, buf, len, 0)) < 0
&& socket_error() == EINTR )
continue;
return length;
}
static int socket_send (socket_t * sock, const void *buf, size_t len)
{
int length;
while ( (length = send (*sock, buf, len, 0)) < 0
&& socket_error() == EINTR )
continue;
return length;
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2004-2009 Georgy Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
static void libirc_add_to_set (int fd, fd_set *set, int * maxfd)
{
FD_SET (fd, set);
if ( *maxfd < fd )
*maxfd = fd;
}
#if defined (ENABLE_DEBUG)
static void libirc_dump_data (const char * prefix, const char * buf, unsigned int length)
{
printf ("%s: ", prefix);
for ( ; length > 0; length -- )
printf ("%c", *buf++);
}
#endif
/*
* Finds a separator (\x0D\x0A), which separates two lines.
*/
static int libirc_findcrlf (const char * buf, int length)
{
int offset = 0;
for ( ; offset < (length - 1); offset++ )
if ( buf[offset] == 0x0D && buf[offset+1] == 0x0A )
return (offset + 2);
return 0;
}
static int libirc_findcrorlf (char * buf, int length)
{
int offset = 0;
for ( ; offset < length; offset++ )
{
if ( buf[offset] == 0x0D || buf[offset] == 0x0A )
{
buf[offset++] = '\0';
if ( offset < (length - 1)
&& (buf[offset] == 0x0D || buf[offset] == 0x0A) )
offset++;
return offset;
}
}
return 0;
}
static void libirc_event_ctcp_internal (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
{
if ( origin )
{
char nickbuf[128], textbuf[256];
irc_target_get_nick (origin, nickbuf, sizeof(nickbuf));
if ( strstr (params[0], "PING") == params[0] )
irc_cmd_ctcp_reply (session, nickbuf, params[0]);
else if ( !strcmp (params[0], "VERSION") )
{
unsigned int high, low;
irc_get_version (&high, &low);
sprintf (textbuf, "VERSION libirc by Georgy Yunaev ver.%d.%d", high, low);
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
}
else if ( !strcmp (params[0], "FINGER") )
{
sprintf (textbuf, "FINGER %s (%s) Idle 0 seconds",
session->username ? session->username : "nobody",
session->realname ? session->realname : "noname");
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
}
else if ( !strcmp (params[0], "TIME") )
{
time_t now = time(0);
#if defined (ENABLE_THREADS) && defined (HAVE_LOCALTIME_R)
struct tm tmtmp, *ltime = localtime_r (&now, &tmtmp);
#else
struct tm * ltime = localtime (&now);
#endif
strftime (textbuf, sizeof(textbuf), "%a %b %e %H:%M:%S %Z %Y", ltime);
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
}
}
}

View File

@@ -0,0 +1,103 @@
# Microsoft Developer Studio Project File - Name="libdynamic" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=libdynamic - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libdynamic.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libdynamic.mak" CFG="libdynamic - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libdynamic - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "libdynamic - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "libdynamic - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "libdynamic-release"
# PROP Intermediate_Dir "libdynamic-release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBDYNAMIC_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "../../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "ENABLE_THREADS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 wsock32.lib /nologo /dll /pdb:none /machine:I386 /out:"libdynamic-release/libircclient.dll"
!ELSEIF "$(CFG)" == "libdynamic - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "libdynamic-debug"
# PROP Intermediate_Dir "libdynamic-debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBDYNAMIC_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "ENABLE_THREADS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 wsock32.lib /nologo /dll /debug /machine:I386 /out:"libdynamic-debug/libircclient.dll" /pdbtype:sept
!ENDIF
# Begin Target
# Name "libdynamic - Win32 Release"
# Name "libdynamic - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\libircclient.c
# End Source File
# Begin Source File
SOURCE=..\libircclient.def
# End Source File
# End Group
# End Target
# End Project

View File

@@ -0,0 +1,56 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "libdynamic"=".\libdynamic.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "libstatic"=".\libstatic.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "spammer"=".\spammer.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name libdynamic
End Project Dependency
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,92 @@
# Microsoft Developer Studio Project File - Name="libstatic" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=libstatic - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libstatic.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libstatic.mak" CFG="libstatic - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libstatic - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "libstatic - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "libstatic - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "libstatic-release"
# PROP Intermediate_Dir "libstatic-release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../../include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "ENABLE_THREADS" /YX /FD /c
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"libstatic-release\libircclient-static.lib"
!ELSEIF "$(CFG)" == "libstatic - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "libstatic-debug"
# PROP Intermediate_Dir "libstatic-debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "ENABLE_THREADS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "libstatic - Win32 Release"
# Name "libstatic - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\libircclient.c
# End Source File
# End Group
# End Target
# End Project

View File

@@ -0,0 +1,24 @@
#!/bin/sh
mkdir -p win32/lib
mkdir -p win32/include
mkdir -p win32/examples
cp libdynamic-release/*.lib win32/lib/
cp libdynamic-release/*.dll win32/lib/
cp libstatic-release/*.lib win32/lib/
cp ../../include/libircclient.h win32/include/
cp ../../include/libirc_errors.h win32/include/
cp ../../include/libirc_events.h win32/include/
cp -r ../../examples/* win32/examples/
cp spammer.dsp win32/examples/
cd win32
zip -r ../libircclient-win32-vc-1.2.zip .
cd ..
rm -rf win32
mkdir doc
cp ../../doc/html/* doc/
cd doc
zip -r ../libircclient-dochtml-1.2.zip .
cd ..
rm -rf doc

View File

@@ -0,0 +1,96 @@
# Microsoft Developer Studio Project File - Name="spammer" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=spammer - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "spammer.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "spammer.mak" CFG="spammer - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "spammer - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "spammer - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "spammer - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 libdynamic-release/libircclient.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "spammer - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 libdynamic-release/libircclient.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "spammer - Win32 Release"
# Name "spammer - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\..\examples\spammer.c
# ADD CPP /I "../../include"
# SUBTRACT CPP /I "../include"
# End Source File
# End Group
# End Target
# End Project