コード例 #1
0
ファイル: conn-zip.c プロジェクト: asterIRC/ngIRCd-xpfx
/**
 * Copy data to the compression buffer of a connection. We do collect
 * some data there until it's full so that we can achieve better
 * compression ratios.
 * If the (pre-)compression buffer is full, we try to flush it ("actually
 * compress some data") and to add the new (uncompressed) data afterwards.
 * This function closes the connection on error.
 * @param Idx Connection handle.
 * @param Data Pointer to the data.
 * @param Len Length of the data to add.
 * @return true on success, false otherwise.
 */
GLOBAL bool
Zip_Buffer( CONN_ID Idx, const char *Data, size_t Len )
{
	size_t buflen;

	assert( Idx > NONE );
	assert( Data != NULL );
	assert( Len > 0 );

	buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
	if (buflen + Len >= WRITEBUFFER_SLINK_LEN) {
		/* compression buffer is full, flush */
		if( ! Zip_Flush( Idx )) return false;
	}

	/* check again; if zip buf is still too large do not append data:
	 * otherwise the zip wbuf would grow too large */
	buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
	if (buflen + Len >= WRITEBUFFER_SLINK_LEN) {
		Log(LOG_ALERT, "Zip Write buffer space exhausted: %lu bytes", buflen + Len);
		Conn_Close(Idx, "Zip Write buffer space exhausted", NULL, false);
		return false;
	}
	return array_catb(&My_Connections[Idx].zip.wbuf, Data, Len);
} /* Zip_Buffer */
コード例 #2
0
ファイル: opentracker.c プロジェクト: mchelen/opentracker_ono
static ssize_t handle_read( const int64 clientsocket ) {
  struct http_data* h = io_getcookie( clientsocket );
  ssize_t l;

  if( ( l = io_tryread( clientsocket, static_inbuf, sizeof static_inbuf ) ) <= 0 ) {
    handle_dead( clientsocket );
    return 0;
  }

  /* If we get the whole request in one packet, handle it without copying */
  if( !array_start( &h->request ) ) {
    if( memchr( static_inbuf, '\n', l ) )
      return http_handle_request( clientsocket, static_inbuf, l );
    h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
    array_catb( &h->request, static_inbuf, l );
    return 0;
  }

  h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
  array_catb( &h->request, static_inbuf, l );

  if( array_failed( &h->request ) )
    return http_issue_error( clientsocket, CODE_HTTPERROR_500 );

  if( ( array_bytes( &h->request ) > 8192 ) && !accesslist_isblessed( (char*)&h->ip, OT_PERMISSION_MAY_SYNC ) )
     return http_issue_error( clientsocket, CODE_HTTPERROR_500 );

  if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) )
    return http_handle_request( clientsocket, array_start( &h->request ), array_bytes( &h->request ) );

  return 0;
}
コード例 #3
0
ファイル: conn-zip.c プロジェクト: asterIRC/ngIRCd-xpfx
/**
 * Compress data in ZIP buffer and move result to the write buffer of
 * the connection.
 * This function closes the connection on error.
 * @param Idx Connection handle.
 * @return true on success, false otherwise.
 */
GLOBAL bool
Zip_Flush( CONN_ID Idx )
{
	int result;
	unsigned char zipbuf[WRITEBUFFER_SLINK_LEN];
	int zipbuf_used = 0;
	z_stream *out;

	out = &My_Connections[Idx].zip.out;

	out->avail_in = (uInt)array_bytes(&My_Connections[Idx].zip.wbuf);
	if (!out->avail_in)
		return true;	/* nothing to do. */

	out->next_in = array_start(&My_Connections[Idx].zip.wbuf);
	assert(out->next_in != NULL);

	out->next_out = zipbuf;
	out->avail_out = (uInt)sizeof zipbuf;

#ifdef DEBUG_ZIP
	Log(LOG_DEBUG, "out->avail_in %d, out->avail_out %d",
		out->avail_in, out->avail_out);
#endif
	result = deflate( out, Z_SYNC_FLUSH );
	if(( result != Z_OK ) || ( out->avail_in > 0 ))
	{
		Log( LOG_ALERT, "Compression error: code %d!?", result );
		Conn_Close( Idx, "Compression error!", NULL, false );
		return false;
	}

	if (out->avail_out <= 0) {
		/* Not all data was compressed, because data became
		 * bigger while compressing it. */
		Log(LOG_ALERT, "Compression error: buffer overflow!?");
		Conn_Close(Idx, "Compression error!", NULL, false);
		return false;
	}

	assert(out->avail_out <= WRITEBUFFER_SLINK_LEN);

	zipbuf_used = WRITEBUFFER_SLINK_LEN - out->avail_out;
#ifdef DEBUG_ZIP
	Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used);
#endif
	if (!array_catb(&My_Connections[Idx].wbuf,
			(char *)zipbuf, (size_t) zipbuf_used)) {
		Log (LOG_ALERT, "Compression error: can't copy data!?");
		Conn_Close(Idx, "Compression error!", NULL, false);
		return false;
	}

	My_Connections[Idx].bytes_out += zipbuf_used;
	My_Connections[Idx].zip.bytes_out += array_bytes(&My_Connections[Idx].zip.wbuf); 
	array_trunc(&My_Connections[Idx].zip.wbuf);

	return true;
} /* Zip_Flush */
コード例 #4
0
unsigned long scan_to_array(unsigned long (*func)(const char*,char*,unsigned long*),
			    const char* src,array* dest) {
  unsigned long scanned;
  unsigned long needed=str_len(src);
  char* x=((char*)array_start(dest))+array_bytes(dest);
  if (!array_allocate(dest,1,array_bytes(dest)+needed-1)) return 0;
  return func(src,x,&scanned);
}
コード例 #5
0
ファイル: z_cdbb.c プロジェクト: oripka/bagunceiro
static int cdbb_handle_ops(struct cdbb *a)
{
	int i;
	int num;
	struct op *t;

	num = 0;

	for (i = 0; i < a->tnum; i++) {
		t = &a->ops[i];

		if (t->kf) {	/* trigger was fired */
			switch (t->t) {
			case O_ADD:
			case O_ADD_MOD:
				/* fall-trought */
			case O_MOD:
				cdb_make_add(a->w,
					(unsigned char *)t->n.p,
					array_bytes(&t->n),
					(unsigned char *)t->v.p,
					array_bytes(&t->v));
				num++;
				break;
			case O_DEL:
				/* do nothing, fall-trough */
			case O_NONE:
			default:
				break;
			}
		} else {
			switch (t->t) {
			case O_ADD_MOD:
				/* key not found so add, fall-trough */
			case O_ADD:
				cdb_make_add(a->w,
					(unsigned char *)t->n.p,
					array_bytes(&t->n),
					(unsigned char *)t->v.p,
					array_bytes(&t->v));
				num++;
				break;
			case O_DEL:
				/* key not found error */
				break;
			case O_MOD:
				/* key not found error */
				break;
			case O_NONE:
				/* fall-trought */
			default:
				break;
			}
		}
	}
	return num;
}
コード例 #6
0
ファイル: array_bytes.c プロジェクト: dpejesh/libsv-common
int main() {
  array_t array = ARRAY_INIT(4);
  array_resize(&array, 3);
  if (array_bytes(&array) != 12)
    return 1;
  array_fail(&array);
  if (array_bytes(&array) != 0)
    return 2;
  return 0;
}
コード例 #7
0
ファイル: fmt_to_array.c プロジェクト: djbtao/libowfat
void fmt_to_array(size_t (*func)(char*,const char*,size_t),
		  array* a,const char* src,size_t len) {
  size_t needed=func(0,src,len);
  if (array_bytes(a)+needed>=needed &&
      array_allocate(a,1,array_bytes(a)+needed-1)) {
    char* x=((char*)array_start(a))+array_bytes(a)-needed;
    func(x,src,len);
  } else
    array_fail(a);
}
コード例 #8
0
void fmt_tofrom_array(unsigned long (*func)(char*,const char*,unsigned long),
		      array* dest,array* src) {
  unsigned long needed;
  char* x;
  if (array_failed(dest) || array_failed(src)) { array_fail(dest); return; }
  needed=func(0,array_start(src),array_bytes(src));
  if (array_allocate(dest,1,array_bytes(dest)+needed-1)) {
    x=((char*)array_start(dest))+array_bytes(dest)-needed;
    func(x,array_start(src),array_bytes(src));
  } else
    array_fail(dest);
}
コード例 #9
0
void fmt_tofrom_array(size_t (*func)(char*,const char*,size_t),
		      array* dest,array* src) {
  size_t needed;
  char* x;
  if (array_failed(dest) || array_failed(src)) { array_fail(dest); return; }
  needed=func(0,array_start(src),array_bytes(src));
  if (array_bytes(dest)+needed>needed &&
      array_allocate(dest,1,array_bytes(dest)+needed-1)) {
    x=((char*)array_start(dest))+array_bytes(dest)-needed;
    func(x,array_start(src),array_bytes(src));
  } else
    array_fail(dest);
}
コード例 #10
0
size_t scan_tofrom_array(size_t (*func)(const char*,char*,size_t*),
			        array* src,array* dest) {
  size_t scanned;
  size_t needed;
  char* x;
  array_cat0(src);
  if (array_failed(src) || array_failed(dest)) return 0;
  needed=array_bytes(src);
  x=((char*)array_start(dest))+array_bytes(dest);
  if (!array_allocate(dest,1,array_bytes(dest)+needed-1)) return 0;
  needed=func(array_start(src),x,&scanned);
  array_truncate(src,1,array_bytes(src)-1);
  return needed;
}
コード例 #11
0
ファイル: irc.c プロジェクト: ngircd/ngircd
/**
 * Handler for the IRC "HELP" command.
 *
 * @param Client The client from which this command has been received.
 * @param Req Request structure with prefix and all parameters.
 * @return CONNECTED or DISCONNECTED.
 */
GLOBAL bool
IRC_HELP(CLIENT *Client, REQUEST *Req)
{
	COMMAND *cmd;

	assert(Client != NULL);
	assert(Req != NULL);

	if ((Req->argc == 0 && array_bytes(&Conf_Helptext) > 0)
	    || (Req->argc >= 1 && strcasecmp(Req->argv[0], "Commands") != 0)) {
		/* Help text available and requested */
		if (Req->argc >= 1)
			return Help(Client, Req->argv[0]);

		if (!Help(Client, "Intro"))
			return DISCONNECTED;
		return CONNECTED;
	}

	cmd = Parse_GetCommandStruct();
	while(cmd->name) {
		if (!IRC_WriteStrClient(Client, "NOTICE %s :%s",
					Client_ID(Client), cmd->name))
			return DISCONNECTED;
		cmd++;
	}
	return CONNECTED;
} /* IRC_HELP */
コード例 #12
0
ファイル: conn-ssl.c プロジェクト: briancollins/ngircd
static bool
ConnSSL_LoadServerKey_gnutls(void)
{
	int err;
	const char *cert_file;

	err = gnutls_certificate_allocate_credentials(&x509_cred);
	if (err < 0) {
		Log(LOG_ERR, "gnutls_certificate_allocate_credentials: %s", gnutls_strerror(err));
		return false;
	}

	cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
	if (!cert_file) {
		Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
		return false;
	}

	if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
		Log(LOG_WARNING,
		    "Ignoring KeyFilePassword: Not supported by GNUTLS.");

	if (!Load_DH_params())
		return false;

	gnutls_certificate_set_dh_params(x509_cred, dh_params);
	err = gnutls_certificate_set_x509_key_file(x509_cred, cert_file, Conf_SSLOptions.KeyFile, GNUTLS_X509_FMT_PEM);
	if (err < 0) {
		Log(LOG_ERR, "gnutls_certificate_set_x509_key_file (cert %s, key %s): %s",
				cert_file, Conf_SSLOptions.KeyFile ? Conf_SSLOptions.KeyFile : "(NULL)", gnutls_strerror(err));
		return false;
	}
	return true;
}
コード例 #13
0
ファイル: channel.c プロジェクト: Flupsy/ngircd
GLOBAL void
Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, const char *Topic)
{
	size_t len;
	assert( Chan != NULL );
	assert( Topic != NULL );

	len = strlen(Topic);
	if (len < array_bytes(&Chan->topic))
		array_free(&Chan->topic);

	if (len >= COMMAND_LEN || !array_copyb(&Chan->topic, Topic, len+1))
		Log(LOG_WARNING, "could not set new Topic \"%s\" on %s: %s",
					Topic, Chan->name, strerror(errno));
#ifndef STRICT_RFC
	Chan->topic_time = time(NULL);
	if (Client != NULL && Client_Type(Client) != CLIENT_SERVER)
		strlcpy(Chan->topic_who, Client_ID(Client),
			sizeof Chan->topic_who);
	else
		strlcpy(Chan->topic_who, DEFAULT_TOPIC_ID,
			sizeof Chan->topic_who);
#else
	(void) Client;
#endif
} /* Channel_SetTopic */
コード例 #14
0
ファイル: channel.c プロジェクト: Flupsy/ngircd
static void
Set_KeyFile(CHANNEL *Chan, const char *KeyFile)
{
	size_t len;

	assert(Chan != NULL);
	assert(KeyFile != NULL);

	len = strlen(KeyFile);
	if (len < array_bytes(&Chan->keyfile)) {
		Log(LOG_INFO, "Channel key file of %s removed.", Chan->name);
		array_free(&Chan->keyfile);
	}

	if (len < 1)
		return;

	if (!array_copyb(&Chan->keyfile, KeyFile, len+1))
		Log(LOG_WARNING,
		    "Could not set new channel key file \"%s\" for %s: %s",
		    KeyFile, Chan->name, strerror(errno));
	else
		Log(LOG_INFO|LOG_snotice,
		    "New local channel key file \"%s\" for %s activated.",
		    KeyFile, Chan->name);
} /* Set_KeyFile */
コード例 #15
0
ファイル: irc.c プロジェクト: ngircd/ngircd
/**
 * Send help for a given topic to the client.
 *
 * @param Client The client requesting help.
 * @param Topic The help topic requested.
 * @return CONNECTED or DISCONNECTED.
 */
static bool
Help(CLIENT *Client, const char *Topic)
{
	char *line;
	size_t helptext_len, len_str, idx_start, lines = 0;
	bool in_article = false;

	assert(Client != NULL);
	assert(Topic != NULL);

	helptext_len = array_bytes(&Conf_Helptext);
	line = array_start(&Conf_Helptext);
	while (helptext_len > 0) {
		len_str = strlen(line) + 1;
		assert(helptext_len >= len_str);
		helptext_len -= len_str;

		if (in_article) {
			/* The first character in each article text line must
			 * be a TAB (ASCII 9) character which will be stripped
			 * in the output. If it is not a TAB, the end of the
			 * article has been reached. */
			if (line[0] != '\t') {
				if (lines > 0)
					return CONNECTED;
				else
					break;
			}

			/* A single '.' character indicates an empty line */
			if (line[1] == '.' && line[2] == '\0')
				idx_start = 2;
			else
				idx_start = 1;

			if (!IRC_WriteStrClient(Client, "NOTICE %s :%s",
						Client_ID(Client),
						&line[idx_start]))
				return DISCONNECTED;
			lines++;

		} else {
			if (line[0] == '-' && line[1] == ' '
			    && strcasecmp(&line[2], Topic) == 0)
				in_article = true;
		}

		line += len_str;
	}

	/* Help topic not found (or empty)! */
	if (!IRC_WriteStrClient(Client, "NOTICE %s :No help for \"%s\" found!",
				Client_ID(Client), Topic))
		return DISCONNECTED;

	return CONNECTED;
}
コード例 #16
0
ファイル: array.c プロジェクト: LucentW/ngircd
/* append trailing NUL byte to array, but do not count it. */
bool
array_cat0_temporary(array * a)
{
	char *endpos = array_alloc(a, 1, array_bytes(a));
	if (!endpos)
		return false;

	*endpos = '\0';
	return true;
}
コード例 #17
0
ファイル: z_entry.c プロジェクト: oripka/bagunceiro
void delete_entry(struct cdbb *a, struct taia *k)
{
	char pk[TAIA_PACK];
	array dayidx;

	memset(&dayidx, 0, sizeof(array));
	fmt_day_idx(&dayidx, k);

	taia_pack(pk, k);

	cdbb_del(a, pk, TAIA_PACK);
	cdbb_del_val(a, dayidx.p, array_bytes(&dayidx), pk, TAIA_PACK);
	blog_modified(a);
}
コード例 #18
0
ファイル: t_array3.c プロジェクト: io7m/coreland-corelib
int main(void)
{
  struct array arr;
  int i;

  test_assert(array_init(&arr, 10, sizeof(int)));
  test_assert(array_bytes(&arr) == 0);
  test_assert(array_size(&arr) == 0);

  for (i = 0; i < 20; ++i) {
    test_assert(array_size(&arr) == i);
    test_assert(array_bytes(&arr) == i * sizeof(int));
    test_assert(array_cat(&arr, &i) == 1);
  }

  test_assert(array_size(&arr) == 20);
  test_assert(array_bytes(&arr) == 20 * sizeof(int));
 
  array_free(&arr);
  test_assert(array_bytes(&arr) == 0);
  test_assert(array_size(&arr) == 0);
  return 0;
}
コード例 #19
0
ファイル: z_cdbb.c プロジェクト: oripka/bagunceiro
/* LEVLEL COPYING LOGIC */
static int cdbb_check_ops(struct cdbb *a, unsigned char *k,
	size_t ks, unsigned char *v, size_t vs)
{
	struct op *t;
	int i, f;
	f = 0;

	for (i = 0; i < a->tnum; i++) {
		t = &a->ops[i];
		if (array_bytes(&t->n) == ks && !memcmp(k, t->n.p, ks) && ks) {
			t->kf = 1;

			if (t->t != O_ADD)
				f = 1;

			/* no value trigger */
			if ((array_bytes(&t->v) != 0)) {
				if (t->t == O_MOD || t->t == O_ADD_MOD)
					continue;

				/* value trigger */
				t->sv = realloc(t->sv, vs);
				if (t->sv == NULL)
					continue;

				memcpy(t->sv, v, vs);

				/* values do match */
				if (!memcmp(t->v.p, t->sv, vs))
					t->vf = 1;
				else
					f = 0;	/* reset found */
			}
		}
	}
	return f;
}
コード例 #20
0
ファイル: z_entry.c プロジェクト: oripka/bagunceiro
void add_entry(struct cdbb *a, struct taia *k, char *v, size_t vs)
{
	char pk[TAIA_PACK];
	array dayidx;

	memset(&dayidx, 0, sizeof(array));
	fmt_day_idx(&dayidx, k);
	taia_pack(pk, k);

	/* entry + idx */
	cdbb_add(a, pk, TAIA_PACK, v, vs);
	cdbb_add(a, dayidx.p, array_bytes(&dayidx), pk, TAIA_PACK);

	blog_modified(a);
	array_reset(&dayidx);
}
コード例 #21
0
ファイル: conn-ssl.c プロジェクト: carriercomm/ngircd
static int
pem_passwd_cb(char *buf, int size, int rwflag, void *password)
{
	array *pass = password;
	int passlen;

	(void)rwflag;		/* rwflag is unused if DEBUG is not set. */
	assert(rwflag == 0);	/* 0 -> callback used for decryption.
				 * See SSL_CTX_set_default_passwd_cb(3) */

	passlen = (int) array_bytes(pass);

	LogDebug("pem_passwd_cb buf size %d, array size %d", size, passlen);
	assert(passlen >= 0);
	if (passlen <= 0) {
		Log(LOG_ERR, "PEM password required but not set [in pem_passwd_cb()]!");
		return 0;
	}
	size = passlen > size ? size : passlen;
	memcpy(buf, (char *)(array_start(pass)), size);
	return size;
}
コード例 #22
0
int64 iob_send(int64 s,io_batch* b) {
  /* Windows has a sendfile called TransmitFile, which can send one
   * header and one trailer buffer. */
  iob_entry* x,* last;
  io_entry* e;
  int64 sent;
  int i;

  if (b->bytesleft==0) return 0;
  sent=-1;
  e=iarray_get(&io_fds,s);
  if (!e) { errno=EBADF; return -3; }
  if (!(x=array_get(&b->b,sizeof(iob_entry),b->next)))
    return -3;		/* can't happen error */
  last=(iob_entry*)(((char*)array_start(&b->b))+array_bytes(&b->b));

  fprintf(stderr,"iob_send() called!\n");
  if (e->canwrite || e->sendfilequeued==1) {
    fprintf(stderr,"...reaping finished WriteFile/TransmitFile.\n");
    /* An overlapping write finished.  Reap the result. */
    if (e->bytes_written==-1) return -3;
    if (e->bytes_written<x->n) {
      sent=e->bytes_written;
      if (x->n < e->bytes_written) {
	e->bytes_written-=x->n;
	x->n=0;
	++x;
      }
      x->n -= e->bytes_written;
      x->offset += e->bytes_written;
      b->bytesleft -= e->bytes_written;
    }
    e->canwrite=0; e->sendfilequeued=0;
  }

  for (i=0; x+i<last; ++i)
    if (x[i].n) break;

  if (x[i].type==FROMBUF) {
    fprintf(stderr,"found non-sent buffer batch entry at %d\n",i);
    if (x+i+1 < last &&
	(x[i+1].type==FROMFILE)) {
      fprintf(stderr,"Next is a file, can use TransmitFile\n",i);
      TRANSMIT_FILE_BUFFERS tfb;
      e->sendfilequeued=1;
      memset(&tfb,0,sizeof(tfb));
      memset(&e[i].os,0,sizeof(e[i].os));
      e[i].os.Offset=x[i].offset;
      e[i].os.OffsetHigh=(x[i].offset>>32);
      fprintf(stderr,"Calling TransmitFile on %p...",s);
      if (!TransmitFile(s,(HANDLE)x[i].fd,
		      x[i].n+tfb.HeadLength>0xffff?0xffff:x[i].n,
		      0,&e[i].os,&tfb,TF_USE_KERNEL_APC)) {
	if (GetLastError()==ERROR_IO_PENDING) {
	  fprintf(stderr," pending.!\n");
	  e->writequeued=1;
	  errno=EAGAIN;
	  e->errorcode=0;
	  return -1;
	} else {
	  fprintf(stderr," failed!\n");
	  e->errorcode=errno;
	  return -3;
	}
      }
      fprintf(stderr," OK!\n");
      return sent;
    } else {
コード例 #23
0
ファイル: conn-zip.c プロジェクト: asterIRC/ngIRCd-xpfx
/**
 * uncompress data and copy it to read buffer.
 * Returns true if data has been unpacked or no
 * compressed data is currently pending in the zread buffer.
 * This function closes the connection on error.
 * @param Idx Connection handle.
 * @return true on success, false otherwise.
 */
GLOBAL bool
Unzip_Buffer( CONN_ID Idx )
{
	int result;
	unsigned char unzipbuf[READBUFFER_LEN];
	int unzipbuf_used = 0;
	unsigned int z_rdatalen;
	unsigned int in_len;
	
	z_stream *in;

	assert( Idx > NONE );

	z_rdatalen = (unsigned int)array_bytes(&My_Connections[Idx].zip.rbuf);
	if (z_rdatalen == 0)
		return true;

	in = &My_Connections[Idx].zip.in;

	in->next_in = array_start(&My_Connections[Idx].zip.rbuf);
	assert(in->next_in != NULL);

	in->avail_in = z_rdatalen;
	in->next_out = unzipbuf;
	in->avail_out = (uInt)sizeof unzipbuf;

#ifdef DEBUG_ZIP
	Log(LOG_DEBUG, "in->avail_in %d, in->avail_out %d",
		in->avail_in, in->avail_out);
#endif
	result = inflate( in, Z_SYNC_FLUSH );
	if( result != Z_OK )
	{
		Log(LOG_ALERT, "Decompression error: %s (code=%d, ni=%d, ai=%d, no=%d, ao=%d)!?", in->msg, result, in->next_in, in->avail_in, in->next_out, in->avail_out);
		Conn_Close(Idx, "Decompression error!", NULL, false);
		return false;
	}

	assert(z_rdatalen >= in->avail_in);
	in_len = z_rdatalen - in->avail_in;
	unzipbuf_used = READBUFFER_LEN - in->avail_out;
#ifdef DEBUG_ZIP
	Log(LOG_DEBUG, "unzipbuf_used: %d - %d = %d", READBUFFER_LEN,
		in->avail_out, unzipbuf_used);
#endif
	assert(unzipbuf_used <= READBUFFER_LEN);
	if (!array_catb(&My_Connections[Idx].rbuf, (char*) unzipbuf,
			(size_t)unzipbuf_used)) {
		Log (LOG_ALERT, "Decompression error: can't copy data!?");
		Conn_Close(Idx, "Decompression error!", NULL, false);
		return false;
	}
	if( in->avail_in > 0 ) {
		array_moveleft(&My_Connections[Idx].zip.rbuf, 1, in_len );
	} else {
		array_trunc( &My_Connections[Idx].zip.rbuf );
		My_Connections[Idx].zip.bytes_in += unzipbuf_used;
	}

	return true;
} /* Unzip_Buffer */