òÅÐÏÚÉÔÏÒÉÉ ALT
5.1: | 3.5.10-alt4 |
4.1: | 3.5.10-alt2.M41.1 |
4.0: | 3.5.9-alt0.M40.1 |
3.0: | 3.4.1-alt4 |
+backports: | 3.5.6-alt2.0.M30 |
çÒÕÐÐÁ :: çÒÁÆÉÞÅÓËÉÅ ÏÂÏÌÏÞËÉ/KDE
ðÁËÅÔ: kdenetwork
çÌÁ×ÎÁÑ éÚÍÅÎÅÎÉÑ óÐÅË ðÁÔÞÉ Sources úÁÇÒÕÚÉÔØ Gear Bugs and FR Repocop
ðÁÔÞ: post-3.4.1-kdenetwork-libgadu.patch
óËÁÞÁÔØ
óËÁÞÁÔØ
Index: kopete/protocols/gadu/libgadu/libgadu.h
===================================================================
--- kopete/protocols/gadu/libgadu/libgadu.h (revision 417278)
+++ kopete/protocols/gadu/libgadu/libgadu.h (working copy)
@@ -33,15 +33,15 @@
extern "C" {
#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
#include <libgadu-config.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdarg.h>
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
#ifdef __GG_LIBGADU_HAVE_OPENSSL
#include <openssl/ssl.h>
#endif
@@ -57,10 +57,10 @@
* ogólna struktura opisuj±ca ró¿ne sesje. przydatna w klientach.
*/
#define gg_common_head(x) \
- int fd; /* podgl±dany deskryptor */ \
- int check; /* sprawdzamy zapis czy odczyt */ \
- int state; /* aktualny stan maszynki */ \
- int error; /* kod b³êdu dla GG_STATE_ERROR */ \
+ int fd; /* podgl±dany deskryptor */ \
+ int check; /* sprawdzamy zapis czy odczyt */ \
+ int state; /* aktualny stan maszynki */ \
+ int error; /* kod b³êdu dla GG_STATE_ERROR */ \
int type; /* rodzaj sesji */ \
int id; /* identyfikator */ \
int timeout; /* sugerowany timeout w sekundach */ \
@@ -111,7 +111,7 @@
char *recv_buf; /* bufor na otrzymywane pakiety */
int recv_done; /* ile ju¿ wczytano do bufora */
- int recv_left; /* i ile jeszcze trzeba wczytaæ */
+ int recv_left; /* i ile jeszcze trzeba wczytaæ */
int protocol_version; /* wersja u¿ywanego protoko³u */
char *client_version; /* wersja u¿ywanego klienta */
@@ -150,17 +150,17 @@
struct gg_http {
gg_common_head(struct gg_http)
- int async; /* czy po³±czenie asynchroniczne */
+ int async; /* czy po³±czenie asynchroniczne */
int pid; /* pid procesu resolvera */
int port; /* port, z którym siê ³±czymy */
- char *query; /* bufor zapytania http */
- char *header; /* bufor nag³ówka */
- int header_size; /* rozmiar wczytanego nag³ówka */
- char *body; /* bufor otrzymanych informacji */
- unsigned int body_size; /* oczekiwana ilo¶æ informacji */
+ char *query; /* bufor zapytania http */
+ char *header; /* bufor nag³ówka */
+ int header_size; /* rozmiar wczytanego nag³ówka */
+ char *body; /* bufor otrzymanych informacji */
+ unsigned int body_size; /* oczekiwana ilo¶æ informacji */
- void *data; /* dane danej operacji http */
+ void *data; /* dane danej operacji http */
char *user_data; /* dane u¿ytkownika, nie s± zwalniane przez gg_http_free() */
@@ -265,27 +265,27 @@
* opisuje stan asynchronicznej maszyny.
*/
enum gg_state_t {
- /* wspólne */
- GG_STATE_IDLE = 0, /* nie powinno wyst±piæ. */
- GG_STATE_RESOLVING, /* wywo³a³ gethostbyname() */
+ /* wspólne */
+ GG_STATE_IDLE = 0, /* nie powinno wyst±piæ. */
+ GG_STATE_RESOLVING, /* wywo³a³ gethostbyname() */
GG_STATE_CONNECTING, /* wywo³a³ connect() */
GG_STATE_READING_DATA, /* czeka na dane http */
GG_STATE_ERROR, /* wyst±pi³ b³±d. kod w x->error */
- /* gg_session */
+ /* gg_session */
GG_STATE_CONNECTING_HUB, /* wywo³a³ connect() na huba */
GG_STATE_CONNECTING_GG, /* wywo³a³ connect() na serwer */
GG_STATE_READING_KEY, /* czeka na klucz */
GG_STATE_READING_REPLY, /* czeka na odpowied¼ */
GG_STATE_CONNECTED, /* po³±czy³ siê */
- /* gg_http */
+ /* gg_http */
GG_STATE_SENDING_QUERY, /* wysy³a zapytanie http */
GG_STATE_READING_HEADER, /* czeka na nag³ówek http */
GG_STATE_PARSING, /* przetwarza dane */
GG_STATE_DONE, /* skoñczy³ */
- /* gg_dcc */
+ /* gg_dcc */
GG_STATE_LISTENING, /* czeka na po³±czenia */
GG_STATE_READING_UIN_1, /* czeka na uin peera */
GG_STATE_READING_UIN_2, /* czeka na swój uin */
@@ -350,8 +350,9 @@
uint16_t external_port; /* port widziany na zewnatrz */
int tls; /* czy ³±czymy po TLS? */
int image_size; /* maksymalny rozmiar obrazka w KiB */
+ int era_omnix; /* czy udawaæ klienta era omnix? */
- char dummy[7 * sizeof(int)]; /* miejsce na kolejnych 8 zmiennych,
+ char dummy[6 * sizeof(int)]; /* miejsce na kolejnych 6 zmiennych,
* ¿eby z dodaniem parametru nie
* zmienia³ siê rozmiar struktury */
};
@@ -500,8 +501,8 @@
*/
struct gg_event {
int type; /* rodzaj zdarzenia -- gg_event_t */
- union { /* @event */
- struct gg_notify_reply *notify; /* informacje o li¶cie kontaktów -- GG_EVENT_NOTIFY */
+ union { /* @event */
+ struct gg_notify_reply *notify; /* informacje o li¶cie kontaktów -- GG_EVENT_NOTIFY */
enum gg_failure_t failure; /* b³±d po³±czenia -- GG_EVENT_FAILURE */
@@ -522,20 +523,20 @@
int formats_length; /* d³ugo¶æ informacji o formatowaniu tekstu */
void *formats; /* informacje o formatowaniu tekstu */
- } msg;
+ } msg;
struct { /* @notify_descr informacje o li¶cie kontaktów z opisami stanu -- GG_EVENT_NOTIFY_DESCR */
struct gg_notify_reply *notify; /* informacje o li¶cie kontaktów */
char *descr; /* opis stanu */
} notify_descr;
- struct { /* @status zmiana stanu -- GG_EVENT_STATUS */
+ struct { /* @status zmiana stanu -- GG_EVENT_STATUS */
uin_t uin; /* numer */
uint32_t status; /* nowy stan */
char *descr; /* opis stanu */
} status;
- struct { /* @status60 zmiana stanu -- GG_EVENT_STATUS60 */
+ struct { /* @status60 zmiana stanu -- GG_EVENT_STATUS60 */
uin_t uin; /* numer */
int status; /* nowy stan */
uint32_t remote_ip; /* adres ip */
@@ -748,6 +749,7 @@
/* przypomnienie has³a e-mailem */
struct gg_http *gg_remind_passwd(uin_t uin, int async);
struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async);
+struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async);
#define gg_remind_passwd_watch_fd gg_pubdir_watch_fd
#define gg_remind_passwd_free gg_pubdir_free
#define gg_free_remind_passwd gg_pubdir_free
@@ -813,6 +815,7 @@
struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin);
void gg_dcc_set_type(struct gg_dcc *d, int type);
int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename);
+int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename);
int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length);
#define GG_DCC_VOICE_FRAME_LENGTH 195
@@ -940,11 +943,12 @@
#define GG_HTTPS_PORT 443
#define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)"
-#define GG_DEFAULT_CLIENT_VERSION "6, 0, 0, 132"
-#define GG_DEFAULT_PROTOCOL_VERSION 0x20
+#define GG_DEFAULT_CLIENT_VERSION "6, 1, 0, 158"
+#define GG_DEFAULT_PROTOCOL_VERSION 0x24
#define GG_DEFAULT_TIMEOUT 30
#define GG_HAS_AUDIO_MASK 0x40000000
-#define GG_LIBGADU_VERSION "20041222"
+#define GG_ERA_OMNIX_MASK 0x04000000
+#define GG_LIBGADU_VERSION "CVS"
#define GG_DEFAULT_DCC_PORT 1550
Index: kopete/protocols/gadu/libgadu/http.c
===================================================================
--- kopete/protocols/gadu/libgadu/http.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/http.c (working copy)
@@ -12,10 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser 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.
+ * You should have received a copy of the GNU Lesser 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 <sys/types.h>
@@ -61,19 +61,19 @@
struct gg_http *h;
if (!hostname || !port || !method || !path || !header) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n");
- errno = EINVAL;
+ gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n");
+ errno = EFAULT;
return NULL;
}
-
+
if (!(h = malloc(sizeof(*h))))
- return NULL;
+ return NULL;
memset(h, 0, sizeof(*h));
h->async = async;
h->port = port;
h->fd = -1;
- h->type = GG_SESSION_HTTP;
+ h->type = GG_SESSION_HTTP;
if (gg_proxy_enabled) {
char *auth = gg_proxy_auth();
@@ -92,12 +92,12 @@
}
if (!h->query) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n");
+ gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n");
free(h);
- errno = ENOMEM;
+ errno = ENOMEM;
return NULL;
}
-
+
gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query);
if (async) {
@@ -106,9 +106,9 @@
#else
if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) {
#endif
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n");
+ gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n");
gg_http_free(h);
- errno = ENOENT;
+ errno = ENOENT;
return NULL;
}
@@ -131,7 +131,7 @@
}
if (!(h->fd = gg_connect(&a, port, 0)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
+ gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
gg_http_free(h);
return NULL;
}
@@ -144,7 +144,7 @@
}
if (h->state != GG_STATE_PARSING) {
- gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n");
+ gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n");
gg_http_free(h);
return NULL;
}
@@ -152,7 +152,7 @@
h->callback = gg_http_watch_fd;
h->destroy = gg_http_free;
-
+
return h;
}
@@ -181,7 +181,7 @@
if (!h) {
gg_debug(GG_DEBUG_MISC, "// gg_http_watch_fd() invalid arguments\n");
- errno = EINVAL;
+ errno = EFAULT;
return -1;
}
@@ -243,7 +243,7 @@
}
if (h->state == GG_STATE_SENDING_QUERY) {
- unsigned int res;
+ int res;
if ((res = write(h->fd, h->query, strlen(h->query))) < 1) {
gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno);
@@ -272,7 +272,7 @@
if (h->state == GG_STATE_READING_HEADER) {
char buf[1024], *tmp;
- unsigned int res;
+ int res;
if ((res = read(h->fd, buf, sizeof(buf))) == -1) {
gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno);
@@ -321,7 +321,7 @@
/* HTTP/1.1 200 OK */
if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) {
- gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);
+ gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);
gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n");
free(h->header);
@@ -332,7 +332,7 @@
h->body_size = 0;
line = h->header;
*tmp = 0;
-
+
gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);
while (line) {
@@ -380,7 +380,7 @@
if (h->state == GG_STATE_READING_DATA) {
char buf[1024];
- unsigned int res;
+ int res;
if ((res = read(h->fd, buf, sizeof(buf))) == -1) {
gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno);
@@ -435,7 +435,7 @@
return 0;
}
-
+
if (h->fd != -1)
close(h->fd);
@@ -452,7 +452,7 @@
* gg_http_stop()
*
* je¶li po³±czenie jest w trakcie, przerywa je. nie zwalnia h->data.
- *
+ *
* - h - struktura opisuj±ca po³±czenie
*/
void gg_http_stop(struct gg_http *h)
@@ -465,7 +465,7 @@
if (h->fd != -1)
close(h->fd);
- h->fd = -1;
+ h->fd = -1;
}
/*
@@ -487,7 +487,7 @@
free(h->query);
h->query = NULL;
}
-
+
if (h->header) {
free(h->header);
h->header = NULL;
Index: kopete/protocols/gadu/libgadu/events.c
===================================================================
--- kopete/protocols/gadu/libgadu/events.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/events.c (working copy)
@@ -14,10 +14,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser 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.
+ * You should have received a copy of the GNU Lesser 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 <sys/types.h>
@@ -56,28 +56,28 @@
void gg_event_free(struct gg_event *e)
{
gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e);
-
+
if (!e)
return;
-
+
switch (e->type) {
case GG_EVENT_MSG:
free(e->event.msg.message);
free(e->event.msg.formats);
free(e->event.msg.recipients);
break;
-
+
case GG_EVENT_NOTIFY:
free(e->event.notify);
break;
-
+
case GG_EVENT_NOTIFY60:
{
int i;
for (i = 0; e->event.notify60[i].uin; i++)
free(e->event.notify60[i].descr);
-
+
free(e->event.notify60);
break;
@@ -86,7 +86,7 @@
case GG_EVENT_STATUS60:
free(e->event.status60.descr);
break;
-
+
case GG_EVENT_STATUS:
free(e->event.status.descr);
break;
@@ -109,7 +109,7 @@
case GG_EVENT_USERLIST:
free(e->event.userlist.reply);
break;
-
+
case GG_EVENT_IMAGE_REPLY:
free(e->event.image_reply.filename);
free(e->event.image_reply.image);
@@ -133,7 +133,7 @@
int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq)
{
if (!s || !q) {
- errno = EINVAL;
+ errno = EFAULT;
return -1;
}
@@ -165,18 +165,20 @@
* parsuje przychodz±cy pakiet z obrazkiem.
*
* - e - opis zdarzenia
- * -
+ * -
*/
-static void gg_image_queue_parse(struct gg_event *e, char *p, int len, struct gg_session *sess, uin_t sender)
+static void gg_image_queue_parse(struct gg_event *e, char *p, unsigned int len, struct gg_session *sess, uin_t sender)
{
struct gg_msg_image_reply *i = (void*) p;
struct gg_image_queue *q, *qq;
- if (!p || !sess || !e)
+ if (!p || !sess || !e) {
+ errno = EFAULT;
return;
+ }
/* znajd¼ dany obrazek w kolejce danej sesji */
-
+
for (qq = sess->images, q = NULL; qq; qq = qq->next) {
if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) {
q = qq;
@@ -191,7 +193,7 @@
if (p[0] == 0x05) {
int i, ok = 0;
-
+
q->done = 0;
len -= sizeof(struct gg_msg_image_reply);
@@ -225,7 +227,7 @@
if (q->done + len > q->size)
len = q->size - q->done;
-
+
memcpy(q->image + q->done, p, len);
q->done += len;
@@ -268,7 +270,7 @@
e->type = GG_EVENT_NONE;
return 0;
}
-
+
for (p = (char*) r + sizeof(*r); *p; p++) {
if (*p == 0x02 && p == packet_end - 1) {
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n");
@@ -279,7 +281,7 @@
goto malformed;
}
}
-
+
p++;
/* przeanalizuj dodatkowe opcje */
@@ -289,9 +291,9 @@
{
struct gg_msg_recipients *m = (void*) p;
uint32_t i, count;
-
+
p += sizeof(*m);
-
+
if (p > packet_end) {
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1)\n");
goto malformed;
@@ -299,40 +301,42 @@
count = gg_fix32(m->count);
- if (p + count * sizeof(uin_t) > packet_end) {
+ if (p + count * sizeof(uin_t) > packet_end || p + count * sizeof(uin_t) < p || count > 0xffff) {
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1.5)\n");
goto malformed;
}
-
+
if (!(e->event.msg.recipients = (void*) malloc(count * sizeof(uin_t)))) {
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for recipients data\n");
- errno = ENOMEM;
goto fail;
}
-
- for (i = 0; i < count; i++, p += sizeof(uin_t))
- e->event.msg.recipients[i] = gg_fix32(*((uint32_t*) p));
-
+
+ for (i = 0; i < count; i++, p += sizeof(uint32_t)) {
+ uint32_t u;
+ memcpy(&u, p, sizeof(uint32_t));
+ e->event.msg.recipients[i] = gg_fix32(u);
+ }
+
e->event.msg.recipients_count = count;
-
+
break;
}
case 0x02: /* richtext */
{
- unsigned short len;
+ uint16_t len;
char *buf;
-
+
if (p + 3 > packet_end) {
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (2)\n");
goto malformed;
}
- len = gg_fix16(*((unsigned short*) (p + 1)));
+ memcpy(&len, p + 1, sizeof(uint16_t));
+ len = gg_fix16(len);
if (!(buf = malloc(len))) {
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for richtext data\n");
- errno = ENOMEM;
goto fail;
}
@@ -343,7 +347,7 @@
free(buf);
goto malformed;
}
-
+
memcpy(buf, p, len);
e->event.msg.formats = buf;
@@ -375,12 +379,29 @@
case 0x05: /* image_reply */
case 0x06:
{
- if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) {
+ struct gg_msg_image_reply *rep = (void*) p;
+
+ if (p + sizeof(struct gg_msg_image_reply) == packet_end) {
+
+ /* pusta odpowied¼ - klient po drugiej stronie nie ma ¿±danego obrazka */
+
+ e->type = GG_EVENT_IMAGE_REPLY;
+ e->event.image_reply.sender = gg_fix32(r->sender);
+ e->event.image_reply.size = 0;
+ e->event.image_reply.crc32 = gg_fix32(rep->crc32);
+ e->event.image_reply.filename = NULL;
+ e->event.image_reply.image = NULL;
+ return 0;
+
+ } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) {
+
gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (4)\n");
goto malformed;
}
- gg_image_queue_parse(e, p, (int)(packet_end - p), sess, gg_fix32(r->sender));
+ rep->size = gg_fix32(rep->size);
+ rep->crc32 = gg_fix32(rep->crc32);
+ gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, gg_fix32(r->sender));
return 0;
}
@@ -443,21 +464,21 @@
}
p = (char*) h + sizeof(struct gg_header);
-
+
switch (h->type) {
case GG_RECV_MSG:
{
if (h->length >= sizeof(struct gg_recv_msg))
if (gg_handle_recv_msg(h, e, sess))
goto fail;
-
+
break;
}
case GG_NOTIFY_REPLY:
{
struct gg_notify_reply *n = (void*) p;
- int count, i;
+ unsigned int count, i;
char *tmp;
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n");
@@ -468,46 +489,45 @@
goto fail;
}
- if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status == GG_STATUS_NOT_AVAIL_DESCR) || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) {
+ if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) {
e->type = GG_EVENT_NOTIFY_DESCR;
-
+
if (!(e->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- errno = ENOMEM;
goto fail;
}
e->event.notify_descr.notify[1].uin = 0;
memcpy(e->event.notify_descr.notify, p, sizeof(*n));
e->event.notify_descr.notify[0].uin = gg_fix32(e->event.notify_descr.notify[0].uin);
e->event.notify_descr.notify[0].status = gg_fix32(e->event.notify_descr.notify[0].status);
+ e->event.notify_descr.notify[0].remote_ip = e->event.notify_descr.notify[0].remote_ip;
e->event.notify_descr.notify[0].remote_port = gg_fix16(e->event.notify_descr.notify[0].remote_port);
count = h->length - sizeof(*n);
if (!(tmp = malloc(count + 1))) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- errno = ENOMEM;
goto fail;
}
memcpy(tmp, p + sizeof(*n), count);
tmp[count] = 0;
e->event.notify_descr.descr = tmp;
-
+
} else {
e->type = GG_EVENT_NOTIFY;
-
+
if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n");
- errno = ENOMEM;
goto fail;
}
-
+
memcpy(e->event.notify, p, h->length);
count = h->length / sizeof(*n);
e->event.notify[count].uin = 0;
-
+
for (i = 0; i < count; i++) {
e->event.notify[i].uin = gg_fix32(e->event.notify[i].uin);
e->event.notify[i].status = gg_fix32(e->event.notify[i].status);
+ e->event.notify[i].remote_ip = e->event.notify[i].remote_ip;
e->event.notify[i].remote_port = gg_fix16(e->event.notify[i].remote_port);
}
}
@@ -557,7 +577,7 @@
}
e->event.notify60[0].uin = 0;
-
+
while (length >= sizeof(struct gg_notify_reply60)) {
uin_t uin = gg_fix32(n->uin);
char *tmp;
@@ -571,6 +591,11 @@
e->event.notify60[i].descr = NULL;
e->event.notify60[i].time = 0;
+ if (uin & 0x40000000)
+ e->event.notify60[i].version |= GG_HAS_AUDIO_MASK;
+ if (uin & 0x08000000)
+ e->event.notify60[i].version |= GG_ERA_OMNIX_MASK;
+
if (GG_S_D(n->status)) {
unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply60));
@@ -585,7 +610,7 @@
/* XXX czas */
}
-
+
length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
} else {
@@ -605,7 +630,7 @@
break;
}
-
+
case GG_STATUS60:
{
struct gg_status60 *s = (void*) p;
@@ -630,6 +655,8 @@
if (uin & 0x40000000)
e->event.status60.version |= GG_HAS_AUDIO_MASK;
+ if (uin & 0x08000000)
+ e->event.status60.version |= GG_ERA_OMNIX_MASK;
if (h->length > sizeof(*s)) {
int len = h->length - sizeof(*s);
@@ -642,8 +669,11 @@
e->event.status60.descr = buf;
- if (len > 4 && p[h->length - 5] == 0)
- e->event.status60.time = *((int*) (p + h->length - 4));
+ if (len > 4 && p[h->length - 5] == 0) {
+ uint32_t t;
+ memcpy(&t, p + h->length - 4, sizeof(uint32_t));
+ e->event.status60.time = gg_fix32(t);
+ }
}
break;
@@ -666,7 +696,7 @@
break;
}
- case GG_PONG:
+ case GG_PONG:
{
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n");
@@ -709,10 +739,10 @@
if (h->length > 1) {
char *tmp;
- int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0;
-
+ unsigned int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0;
+
gg_debug(GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len);
-
+
if (!(tmp = realloc(sess->userlist_reply, len + h->length))) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n");
free(sess->userlist_reply);
@@ -739,7 +769,7 @@
default:
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type);
}
-
+
free(h);
return 0;
@@ -767,9 +797,10 @@
struct gg_event *e;
int res = 0;
int port = 0;
+ int errno2 = 0;
gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess);
-
+
if (!sess) {
errno = EFAULT;
return NULL;
@@ -793,8 +824,9 @@
if (read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n");
failed = 1;
+ errno2 = errno;
}
-
+
close(sess->fd);
sess->fd = -1;
@@ -809,8 +841,10 @@
}
#endif
- if (failed)
+ if (failed) {
+ errno = errno2;
goto fail_resolving;
+ }
/* je¶li jeste¶my w resolverze i mamy ustawiony port
* proxy, znaczy, ¿e resolvowali¶my proxy. zatem
@@ -829,7 +863,7 @@
}
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port);
-
+
/* ³±czymy siê albo z hubem, albo z proxy, zale¿nie
* od tego, co resolvowali¶my. */
if ((sess->fd = gg_connect(&addr, port, sess->async)) == -1) {
@@ -866,7 +900,7 @@
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
goto fail_connecting;
}
-
+
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s), trying direct connection\n", res, strerror(res));
close(sess->fd);
@@ -884,7 +918,7 @@
sess->timeout = GG_DEFAULT_TIMEOUT;
break;
}
-
+
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n");
if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) {
@@ -911,12 +945,12 @@
"Host: " GG_APPMSG_HOST "\r\n"
"User-Agent: " GG_HTTP_USERAGENT "\r\n"
"Pragma: no-cache\r\n"
- "%s"
+ "%s"
"\r\n", host, appmsg, sess->uin, client, sess->last_sysmsg, (auth) ? auth : "");
if (auth)
free(auth);
-
+
free(client);
/* zwolnij pamiêæ po wersji klienta. */
@@ -925,8 +959,8 @@
sess->client_version = NULL;
}
- gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf);
-
+ gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf);
+
/* zapytanie jest krótkie, wiêc zawsze zmie¶ci siê
* do bufora gniazda. je¶li write() zwróci mniej,
* sta³o siê co¶ z³ego. */
@@ -960,7 +994,7 @@
gg_read_line(sess->fd, buf, sizeof(buf) - 1);
gg_chomp(buf);
gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf);
-
+
/* sprawdzamy, czy wszystko w porz±dku. */
if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() that's not what we've expected, trying direct connection\n");
@@ -981,7 +1015,7 @@
sess->timeout = GG_DEFAULT_TIMEOUT;
break;
}
-
+
sess->port = GG_DEFAULT_PORT;
/* ³±czymy siê na port 8074 huba. */
@@ -989,20 +1023,20 @@
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno));
sess->port = GG_HTTPS_PORT;
-
+
/* ³±czymy siê na port 443. */
if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
goto fail_connecting;
}
}
-
+
sess->state = GG_STATE_CONNECTING_GG;
sess->check = GG_CHECK_WRITE;
sess->timeout = GG_DEFAULT_TIMEOUT;
break;
}
-
+
/* ignorujemy resztê nag³ówka. */
while (strcmp(buf, "\r\n") && strcmp(buf, ""))
gg_read_line(sess->fd, buf, sizeof(buf) - 1);
@@ -1010,13 +1044,13 @@
/* czytamy pierwsz± liniê danych. */
gg_read_line(sess->fd, buf, sizeof(buf) - 1);
gg_chomp(buf);
-
+
/* je¶li pierwsza liczba w linii nie jest równa zeru,
* oznacza to, ¿e mamy wiadomo¶æ systemow±. */
if (atoi(buf)) {
char tmp[1024], *foo, *sysmsg_buf = NULL;
int len = 0;
-
+
while (gg_read_line(sess->fd, tmp, sizeof(tmp) - 1)) {
if (!(foo = realloc(sysmsg_buf, len + strlen(tmp) + 2))) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n");
@@ -1029,23 +1063,23 @@
strcpy(sysmsg_buf, tmp);
else
strcat(sysmsg_buf, tmp);
-
+
len += strlen(tmp);
}
-
+
e->type = GG_EVENT_MSG;
e->event.msg.msgclass = atoi(buf);
e->event.msg.sender = 0;
e->event.msg.message = sysmsg_buf;
}
-
+
close(sess->fd);
-
+
gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
/* analizujemy otrzymane dane. */
tmp = buf;
-
+
while (*tmp && *tmp != ' ')
tmp++;
while (*tmp && *tmp == ' ')
@@ -1057,7 +1091,7 @@
if ((tmp = strchr(host, ':'))) {
*tmp = 0;
- port = atoi(tmp+1);
+ port = atoi(tmp + 1);
}
addr.s_addr = inet_addr(host);
@@ -1070,7 +1104,7 @@
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
goto fail_connecting;
}
-
+
sess->state = GG_STATE_CONNECTING_GG;
sess->check = GG_CHECK_WRITE;
sess->timeout = GG_DEFAULT_TIMEOUT;
@@ -1097,7 +1131,7 @@
sess->state = GG_STATE_CONNECTING_GG;
sess->check = GG_CHECK_WRITE;
sess->timeout = GG_DEFAULT_TIMEOUT;
-
+
break;
}
@@ -1149,18 +1183,24 @@
}
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected\n");
-
+
if (gg_proxy_http_only)
sess->proxy_port = 0;
/* je¶li mamy proxy, wy¶lijmy zapytanie. */
if (sess->proxy_addr && sess->proxy_port) {
char buf[100], *auth = gg_proxy_auth();
+ struct in_addr addr;
- snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(*((struct in_addr*) &sess->server_addr)), sess->port);
+ if (sess->server_addr)
+ addr.s_addr = sess->server_addr;
+ else
+ addr.s_addr = sess->hub_addr;
+ snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(addr), sess->port);
+
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf);
-
+
/* wysy³amy zapytanie. jest ono na tyle krótkie,
* ¿e musi siê zmie¶ciæ w buforze gniazda. je¶li
* write() zawiedzie, sta³o siê co¶ z³ego. */
@@ -1225,7 +1265,7 @@
sess->fd = -1;
break;
}
-
+
if (err == SSL_ERROR_WANT_READ) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n");
@@ -1248,7 +1288,7 @@
ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf);
-
+
e->type = GG_EVENT_CONN_FAILED;
e->event.failure = GG_FAILURE_TLS;
sess->state = GG_STATE_IDLE;
@@ -1284,13 +1324,13 @@
case GG_STATE_READING_KEY:
{
- struct gg_header *h;
+ struct gg_header *h;
struct gg_welcome *w;
struct gg_login60 l;
unsigned int hash;
unsigned char *password = sess->password;
int ret;
-
+
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n");
memset(&l, 0, sizeof(l));
@@ -1305,7 +1345,7 @@
gg_read_line(sess->fd, buf, sizeof(buf) - 1);
gg_chomp(buf);
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf);
-
+
while (strcmp(buf, "")) {
gg_read_line(sess->fd, buf, sizeof(buf) - 1);
gg_chomp(buf);
@@ -1316,7 +1356,7 @@
/* XXX niech czeka jeszcze raz w tej samej
* fazie. g³upio, ale dzia³a. */
sess->proxy_port = 0;
-
+
break;
}
@@ -1327,7 +1367,9 @@
e->type = GG_EVENT_CONN_FAILED;
e->event.failure = GG_FAILURE_READING;
sess->state = GG_STATE_IDLE;
+ errno2 = errno;
close(sess->fd);
+ errno = errno2;
sess->fd = -1;
break;
}
@@ -1343,21 +1385,25 @@
sess->state = GG_STATE_IDLE;
break;
}
-
+
w = (struct gg_welcome*) ((char*) h + sizeof(struct gg_header));
w->key = gg_fix32(w->key);
hash = gg_login_hash(password, w->key);
-
+
gg_debug(GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> hash %.8x\n", w->key, hash);
-
+
free(h);
free(sess->password);
sess->password = NULL;
- gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(*((struct in_addr*) &gg_dcc_ip)));
-
+ {
+ struct in_addr dcc_ip;
+ dcc_ip.s_addr = gg_dcc_ip;
+ gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(dcc_ip));
+ }
+
if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
struct sockaddr_in sin;
int sin_len = sizeof(sin);
@@ -1371,19 +1417,19 @@
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
l.local_ip = 0;
}
- } else
+ } else
l.local_ip = gg_dcc_ip;
-
+
l.uin = gg_fix32(sess->uin);
l.hash = gg_fix32(hash);
l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL);
l.version = gg_fix32(sess->protocol_version);
l.local_port = gg_fix16(gg_dcc_port);
l.image_size = sess->image_size;
-
+
if (sess->external_addr && sess->external_port > 1023) {
l.external_ip = sess->external_addr;
- l.external_port = sess->external_port;
+ l.external_port = gg_fix16(sess->external_port);
}
gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN60 packet\n");
@@ -1394,15 +1440,16 @@
if (ret == -1) {
gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno));
-
+ errno2 = errno;
close(sess->fd);
+ errno = errno2;
sess->fd = -1;
e->type = GG_EVENT_CONN_FAILED;
e->event.failure = GG_FAILURE_WRITING;
sess->state = GG_STATE_IDLE;
break;
}
-
+
sess->state = GG_STATE_READING_REPLY;
break;
@@ -1419,11 +1466,13 @@
e->type = GG_EVENT_CONN_FAILED;
e->event.failure = GG_FAILURE_READING;
sess->state = GG_STATE_IDLE;
+ errno2 = errno;
close(sess->fd);
+ errno = errno2;
sess->fd = -1;
break;
}
-
+
if (h->type == GG_LOGIN_OK) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n");
e->type = GG_EVENT_CONN_SUCCESS;
@@ -1450,7 +1499,9 @@
e->type = GG_EVENT_CONN_FAILED;
sess->state = GG_STATE_IDLE;
+ errno2 = errno;
close(sess->fd);
+ errno = errno2;
sess->fd = -1;
free(h);
@@ -1462,7 +1513,7 @@
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
sess->last_event = time(NULL);
-
+
if ((res = gg_watch_fd_connected(sess, e)) == -1) {
gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno));
@@ -1484,10 +1535,12 @@
}
return e;
-
+
fail_connecting:
if (sess->fd != -1) {
+ errno2 = errno;
close(sess->fd);
+ errno = errno2;
sess->fd = -1;
}
e->type = GG_EVENT_CONN_FAILED;
Index: kopete/protocols/gadu/libgadu/pubdir.c
===================================================================
--- kopete/protocols/gadu/libgadu/pubdir.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/pubdir.c (working copy)
@@ -13,10 +13,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser 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.
+ * You should have received a copy of the GNU Lesser 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 <ctype.h>
@@ -46,12 +46,12 @@
*/
struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async)
{
- struct gg_http *h;
+ struct gg_http *h;
char *__pwd, *__email, *__tokenid, *__tokenval, *form, *query;
- if (!email | !password | !tokenid | !tokenval) {
+ if (!email || !password || !tokenid || !tokenval) {
gg_debug(GG_DEBUG_MISC, "=> register, NULL parameter\n");
- errno = EINVAL;
+ errno = EFAULT;
return NULL;
}
@@ -66,7 +66,6 @@
free(__email);
free(__tokenid);
free(__tokenval);
- errno = ENOMEM;
return NULL;
}
@@ -81,7 +80,6 @@
if (!form) {
gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form query\n");
- errno = ENOMEM;
return NULL;
}
@@ -99,10 +97,15 @@
free(form);
+ if (!query) {
+ gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for query\n");
+ return NULL;
+ }
+
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> register, gg_http_connect() failed mysteriously\n");
free(query);
- return NULL;
+ return NULL;
}
h->type = GG_SESSION_REGISTER;
@@ -111,10 +114,10 @@
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
-
+
if (!async)
gg_pubdir_watch_fd(h);
-
+
return h;
}
@@ -139,10 +142,10 @@
if (!password || !tokenid || !tokenval) {
gg_debug(GG_DEBUG_MISC, "=> unregister, NULL parameter\n");
- errno = EINVAL;
+ errno = EFAULT;
return NULL;
}
-
+
__pwd = gg_saprintf("%ld", random());
__fmpwd = gg_urlencode(password);
__tokenid = gg_urlencode(tokenid);
@@ -154,7 +157,6 @@
free(__fmpwd);
free(__tokenid);
free(__tokenval);
- errno = ENOMEM;
return NULL;
}
@@ -167,7 +169,6 @@
if (!form) {
gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n");
- errno = ENOMEM;
return NULL;
}
@@ -185,6 +186,11 @@
free(form);
+ if (!query) {
+ gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for query\n");
+ return NULL;
+ }
+
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> unregister, gg_http_connect() failed mysteriously\n");
free(query);
@@ -197,10 +203,10 @@
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
-
+
if (!async)
gg_pubdir_watch_fd(h);
-
+
return h;
}
@@ -228,10 +234,10 @@
if (!uin || !email || !passwd || !newpasswd || !tokenid || !tokenval) {
gg_debug(GG_DEBUG_MISC, "=> change, NULL parameter\n");
- errno = EINVAL;
+ errno = EFAULT;
return NULL;
}
-
+
__fmpwd = gg_urlencode(passwd);
__pwd = gg_urlencode(newpasswd);
__email = gg_urlencode(email);
@@ -245,10 +251,9 @@
free(__email);
free(__tokenid);
free(__tokenval);
- errno = ENOMEM;
return NULL;
}
-
+
if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) {
gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
free(__fmpwd);
@@ -257,33 +262,37 @@
free(__tokenid);
free(__tokenval);
- errno = ENOMEM;
return NULL;
}
-
+
free(__fmpwd);
free(__pwd);
free(__email);
free(__tokenid);
free(__tokenval);
-
+
gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);
- query = gg_saprintf(
+ query = gg_saprintf(
"Host: " GG_REGISTER_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: %d\r\n"
- "Pragma: no-cache\r\n"
- "\r\n"
- "%s",
- (int) strlen(form), form);
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "User-Agent: " GG_HTTP_USERAGENT "\r\n"
+ "Content-Length: %d\r\n"
+ "Pragma: no-cache\r\n"
+ "\r\n"
+ "%s",
+ (int) strlen(form), form);
free(form);
+ if (!query) {
+ gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for query\n");
+ return NULL;
+ }
+
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> change, gg_http_connect() failed mysteriously\n");
- free(query);
+ free(query);
return NULL;
}
@@ -301,11 +310,12 @@
}
/*
- * gg_remind_passwd()
+ * gg_remind_passwd3()
*
* wysy³a ¿±danie przypomnienia has³a e-mailem.
*
* - uin - numer
+ * - email - adres e-mail taki, jak ten zapisany na serwerze
* - async - po³±czenie asynchroniczne
* - tokenid - identyfikator tokenu
* - tokenval - warto¶æ tokenu
@@ -313,56 +323,63 @@
* zaalokowana struct gg_http, któr± po¼niej nale¿y zwolniæ
* funkcj± gg_remind_passwd_free(), albo NULL je¶li wyst±pi³ b³±d.
*/
-struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async)
+struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async)
{
struct gg_http *h;
- char *form, *query, *__tokenid, *__tokenval;
+ char *form, *query, *__tokenid, *__tokenval, *__email;
- if (!tokenid || !tokenval) {
+ if (!tokenid || !tokenval || !email) {
gg_debug(GG_DEBUG_MISC, "=> remind, NULL parameter\n");
- errno = EINVAL;
+ errno = EFAULT;
return NULL;
}
-
+
__tokenid = gg_urlencode(tokenid);
__tokenval = gg_urlencode(tokenval);
+ __email = gg_urlencode(email);
- if (!__tokenid || !__tokenval) {
+ if (!__tokenid || !__tokenval || !__email) {
gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
free(__tokenid);
free(__tokenval);
- errno = ENOMEM;
+ free(__email);
return NULL;
}
- if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval))) {
+ if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&email=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval, __email))) {
gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
- errno = ENOMEM;
free(__tokenid);
free(__tokenval);
+ free(__email);
return NULL;
}
free(__tokenid);
free(__tokenval);
-
+ free(__email);
+
gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form);
- query = gg_saprintf(
+ query = gg_saprintf(
"Host: " GG_REMIND_HOST "\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "User-Agent: " GG_HTTP_USERAGENT "\r\n"
- "Content-Length: %d\r\n"
- "Pragma: no-cache\r\n"
- "\r\n"
- "%s",
- (int) strlen(form), form);
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "User-Agent: " GG_HTTP_USERAGENT "\r\n"
+ "Content-Length: %d\r\n"
+ "Pragma: no-cache\r\n"
+ "\r\n"
+ "%s",
+ (int) strlen(form), form);
free(form);
+ if (!query) {
+ gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for query\n");
+ return NULL;
+ }
+
if (!(h = gg_http_connect(GG_REMIND_HOST, GG_REMIND_PORT, async, "POST", "/appsvc/fmsendpwd3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> remind, gg_http_connect() failed mysteriously\n");
- free(query);
+ free(query);
return NULL;
}
@@ -397,36 +414,37 @@
char *tmp;
if (!h) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (h->state == GG_STATE_ERROR) {
+ gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n");
errno = EINVAL;
return -1;
}
-
- if (h->state == GG_STATE_ERROR) {
- gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n");
- errno = EINVAL;
- return -1;
- }
-
+
if (h->state != GG_STATE_PARSING) {
if (gg_http_watch_fd(h) == -1) {
gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n");
- errno = EINVAL;
+ errno = EINVAL;
return -1;
}
}
if (h->state != GG_STATE_PARSING)
- return 0;
-
- h->state = GG_STATE_DONE;
-
+ return 0;
+
+ h->state = GG_STATE_DONE;
+
if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) {
gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n");
return -1;
}
+
p->success = 0;
p->uin = 0;
-
+
gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body);
if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) {
@@ -451,7 +469,7 @@
{
if (!h)
return;
-
+
free(h->data);
gg_http_free(h);
}
@@ -486,10 +504,10 @@
h->callback = gg_token_watch_fd;
h->destroy = gg_token_free;
-
+
if (!async)
gg_token_watch_fd(h);
-
+
return h;
}
@@ -508,33 +526,34 @@
int gg_token_watch_fd(struct gg_http *h)
{
if (!h) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (h->state == GG_STATE_ERROR) {
+ gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n");
errno = EINVAL;
return -1;
}
-
- if (h->state == GG_STATE_ERROR) {
- gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n");
- errno = EINVAL;
- return -1;
- }
-
+
if (h->state != GG_STATE_PARSING) {
if (gg_http_watch_fd(h) == -1) {
gg_debug(GG_DEBUG_MISC, "=> token, http failure\n");
- errno = EINVAL;
+ errno = EINVAL;
return -1;
}
}
if (h->state != GG_STATE_PARSING)
- return 0;
-
+ return 0;
+
/* je¶li h->data jest puste, to ¶ci±gali¶my tokenid i url do niego,
* ale je¶li co¶ tam jest, to znaczy, ¿e mamy drugi etap polegaj±cy
* na pobieraniu tokenu. */
if (!h->data) {
int width, height, length;
- char *url = NULL, *tokenid = NULL, *path;
+ char *url = NULL, *tokenid = NULL, *path, *headers;
+ const char *host;
struct gg_http *h2;
struct gg_token *t;
@@ -545,34 +564,64 @@
free(url);
return -1;
}
-
+
if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) {
gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n");
free(url);
free(tokenid);
+ errno = EINVAL;
return -1;
}
-
+
/* dostali¶my tokenid i wszystkie niezbêdne informacje,
* wiêc pobierzmy obrazek z tokenem */
- if (!(path = gg_saprintf("%s?tokenid=%s", url, tokenid))) {
+ if (strncmp(url, "http://", 7)) {
+ path = gg_saprintf("%s?tokenid=%s", url, tokenid);
+ host = GG_REGISTER_HOST;
+ } else {
+ char *slash = strchr(url + 7, '/');
+
+ if (slash) {
+ path = gg_saprintf("%s?tokenid=%s", slash, tokenid);
+ *slash = 0;
+ host = url + 7;
+ } else {
+ gg_debug(GG_DEBUG_MISC, "=> token, url parsing failed\n");
+ free(url);
+ free(tokenid);
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ if (!path) {
gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
free(url);
free(tokenid);
return -1;
}
- free(url);
+ if (!(headers = gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n", host))) {
+ gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
+ free(path);
+ free(url);
+ free(tokenid);
+ return -1;
+ }
- if (!(h2 = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, h->async, "GET", path, "Host: " GG_REGISTER_HOST "\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n"))) {
+ if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) {
gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
+ free(headers);
+ free(url);
free(path);
free(tokenid);
return -1;
}
+ free(headers);
free(path);
+ free(url);
memcpy(h, h2, sizeof(struct gg_http));
free(h2);
@@ -581,7 +630,7 @@
h->callback = gg_token_watch_fd;
h->destroy = gg_token_free;
-
+
if (!h->async)
gg_token_watch_fd(h);
@@ -599,7 +648,7 @@
/* obrazek mamy w h->body */
h->state = GG_STATE_DONE;
}
-
+
return 0;
}
@@ -619,7 +668,7 @@
if ((t = h->data))
free(t->tokenid);
-
+
free(h->data);
gg_http_free(h);
}
Index: kopete/protocols/gadu/libgadu/libgadu.c
===================================================================
--- kopete/protocols/gadu/libgadu/libgadu.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/libgadu.c (working copy)
@@ -107,9 +107,9 @@
#else
return (uint32_t)
(((x & (uint32_t) 0x000000ffU) << 24) |
- ((x & (uint32_t) 0x0000ff00U) << 8) |
- ((x & (uint32_t) 0x00ff0000U) >> 8) |
- ((x & (uint32_t) 0xff000000U) >> 24));
+ ((x & (uint32_t) 0x0000ff00U) << 8) |
+ ((x & (uint32_t) 0x00ff0000U) >> 8) |
+ ((x & (uint32_t) 0xff000000U) >> 24));
#endif
}
@@ -131,7 +131,7 @@
#else
return (uint16_t)
(((x & (uint16_t) 0x00ffU) << 8) |
- ((x & (uint16_t) 0xff00U) >> 8));
+ ((x & (uint16_t) 0xff00U) >> 8));
#endif
}
@@ -187,6 +187,7 @@
{
int pipes[2], res;
struct in_addr a;
+ int errno2;
gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname);
@@ -199,8 +200,10 @@
return -1;
if ((res = fork()) == -1) {
+ errno2 = errno;
close(pipes[0]);
close(pipes[1]);
+ errno = errno2;
return -1;
}
@@ -297,7 +300,6 @@
if (!(tmp = malloc(sizeof(pthread_t)))) {
gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n");
- errno = ENOMEM;
return -1;
}
@@ -309,7 +311,7 @@
if (!(d = malloc(sizeof(*d)))) {
gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
- new_errno = ENOMEM;
+ new_errno = errno;
goto cleanup;
}
@@ -317,7 +319,7 @@
if (!(d->hostname = strdup(hostname))) {
gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
- new_errno = ENOMEM;
+ new_errno = errno;
goto cleanup;
}
@@ -406,7 +408,7 @@
*/
int gg_write(struct gg_session *sess, const char *buf, int length)
{
- int res;
+ int res = 0;
#ifdef __GG_LIBGADU_HAVE_OPENSSL
if (sess->ssl) {
@@ -453,13 +455,16 @@
*
* - sess - opis sesji
*
- * w przypadku b³êdu NULL, kod b³êdu w errno.
+ * w przypadku b³êdu NULL, kod b³êdu w errno. nale¿y zwróciæ uwagê, ¿e gdy
+ * po³±czenie jest nieblokuj±ce, a kod b³êdu wynosi EAGAIN, nie uda³o siê
+ * odczytaæ ca³ego pakietu i nie nale¿y tego traktowaæ jako b³±d.
*/
void *gg_recv_packet(struct gg_session *sess)
{
struct gg_header h;
char *buf = NULL;
- int ret = 0, offset, size = 0;
+ int ret = 0;
+ unsigned int offset, size = 0;
gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess);
@@ -483,7 +488,7 @@
gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret);
if (!ret) {
- errno = 0;
+ errno = ECONNRESET;
gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n");
return NULL;
}
@@ -522,7 +527,7 @@
memcpy(&h, sess->recv_buf, sizeof(h));
/* jakie¶ sensowne limity na rozmiar pakietu */
- if (h.length < 0 || h.length > 65535) {
+ if (h.length > 65535) {
gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length);
errno = ERANGE;
return NULL;
@@ -548,11 +553,20 @@
while (size > 0) {
ret = gg_read(sess, buf + sizeof(h) + offset, size);
gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret);
+ if (!ret) {
+ gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
+ errno = ECONNRESET;
+ return NULL;
+ }
if (ret > -1 && ret <= size) {
offset += ret;
size -= ret;
} else if (ret == -1) {
+ int errno2 = errno;
+
gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno));
+ errno = errno2;
+
if (errno == EAGAIN) {
gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
sess->recv_buf = buf;
@@ -603,9 +617,9 @@
{
struct gg_header *h;
char *tmp;
- int tmp_length;
+ unsigned int tmp_length;
void *payload;
- int payload_length;
+ unsigned int payload_length;
va_list ap;
int res;
@@ -625,11 +639,8 @@
while (payload) {
char *tmp2;
- payload_length = va_arg(ap, int);
+ payload_length = va_arg(ap, unsigned int);
- if (payload_length < 0)
- gg_debug(GG_DEBUG_MISC, "// gg_send_packet() invalid payload length (%d)\n", payload_length);
-
if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) {
gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n");
free(tmp);
@@ -679,7 +690,7 @@
static int gg_session_callback(struct gg_session *s)
{
if (!s) {
- errno = EINVAL;
+ errno = EFAULT;
return -1;
}
@@ -709,7 +720,7 @@
if (!p) {
gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p);
- errno = EINVAL;
+ errno = EFAULT;
return NULL;
}
@@ -724,7 +735,7 @@
if (!p->password || !p->uin) {
gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. uin and password needed\n");
- errno = EINVAL;
+ errno = EFAULT;
goto fail;
}
@@ -743,7 +754,7 @@
sess->check = GG_CHECK_READ;
sess->timeout = GG_DEFAULT_TIMEOUT;
sess->async = p->async;
- sess->type = GG_SESSION_GG;
+ sess->type = GG_SESSION_GG;
sess->initial_status = p->status;
sess->callback = gg_session_callback;
sess->destroy = gg_free_session;
@@ -752,6 +763,8 @@
sess->external_port = p->external_port;
sess->external_addr = p->external_addr;
sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION;
+ if (p->era_omnix)
+ sess->protocol_version |= GG_ERA_OMNIX_MASK;
if (p->has_audio)
sess->protocol_version |= GG_HAS_AUDIO_MASK;
sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL;
@@ -1092,7 +1105,7 @@
#endif
if (sess->fd != -1) {
- shutdown(sess->fd, 2);
+ shutdown(sess->fd, SHUT_RDWR);
close(sess->fd);
sess->fd = -1;
}
@@ -1129,6 +1142,11 @@
return -1;
}
+ if (size < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
s.recipient = gg_fix32(recipient);
s.seq = gg_fix32(0);
s.msgclass = gg_fix32(GG_CLASS_MSG);
@@ -1141,15 +1159,21 @@
if (!res) {
struct gg_image_queue *q = malloc(sizeof(*q));
- char *buf = malloc(size);
+ char *buf;
if (!q) {
gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n");
- free(buf);
- errno = ENOMEM;
return -1;
}
+ buf = malloc(size);
+ if (size && !buf)
+ {
+ gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n");
+ free(q);
+ return -1;
+ }
+
memset(q, 0, sizeof(*q));
q->sender = recipient;
@@ -1191,7 +1215,7 @@
struct gg_send_msg s;
const char *tmp;
char buf[1910];
- int res;
+ int res = -1;
gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size);
@@ -1200,6 +1224,16 @@
return -1;
}
+ if (sess->state != GG_STATE_CONNECTED) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ if (size < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
/* wytnij ¶cie¿ki, zostaw tylko nazwê pliku */
while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\')))
filename = tmp + 1;
@@ -1209,11 +1243,6 @@
return -1;
}
- if (sess->state != GG_STATE_CONNECTED) {
- errno = ENOTCONN;
- return -1;
- }
-
s.recipient = gg_fix32(recipient);
s.seq = gg_fix32(0);
s.msgclass = gg_fix32(GG_CLASS_MSG);
@@ -1336,12 +1365,17 @@
errno = EFAULT;
return -1;
}
-
+
if (sess->state != GG_STATE_CONNECTED) {
errno = ENOTCONN;
return -1;
}
+ if (!message) {
+ errno = EFAULT;
+ return -1;
+ }
+
s.recipient = gg_fix32(recipient);
if (!sess->seq)
sess->seq = 0x01740000 | (rand() & 0xffff);
@@ -1406,12 +1440,17 @@
errno = EFAULT;
return -1;
}
-
+
if (sess->state != GG_STATE_CONNECTED) {
errno = ENOTCONN;
return -1;
}
+ if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) {
+ errno = EINVAL;
+ return -1;
+ }
+
r.flag = 0x01;
r.count = gg_fix32(recipients_count - 1);
@@ -1421,6 +1460,9 @@
s.msgclass = gg_fix32(msgclass);
recps = malloc(sizeof(uin_t) * recipients_count);
+ if (!recps)
+ return -1;
+
for (i = 0; i < recipients_count; i++) {
s.recipient = gg_fix32(recipients[i]);
@@ -1722,10 +1764,15 @@
int len;
if (!sess) {
- errno = EINVAL;
+ errno = EFAULT;
return -1;
}
+ if (sess->state != GG_STATE_CONNECTED) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
if (!request) {
sess->userlist_blocks = 1;
return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL);
Index: kopete/protocols/gadu/libgadu/common.c
===================================================================
--- kopete/protocols/gadu/libgadu/common.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/common.c (working copy)
@@ -13,10 +13,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser 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.
+ * You should have received a copy of the GNU Lesser 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 <sys/types.h>
@@ -39,7 +39,7 @@
#include "libgadu.h"
-FILE *gg_debug_file;
+FILE *gg_debug_file = NULL;
#ifndef GG_DEBUG_DISABLE
@@ -55,7 +55,7 @@
{
va_list ap;
int old_errno = errno;
-
+
if (gg_debug_handler) {
va_start(ap, format);
(*gg_debug_handler)(level, format, ap);
@@ -63,7 +63,7 @@
goto cleanup;
}
-
+
if ((gg_debug_level & level)) {
va_start(ap, format);
vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap);
@@ -91,10 +91,10 @@
*/
char *gg_vsaprintf(const char *format, va_list ap)
{
- int size = 0;
+ int size = 0;
const char *start;
char *buf = NULL;
-
+
#ifdef __GG_LIBGADU_HAVE_VA_COPY
va_list aq;
@@ -107,13 +107,13 @@
# endif
#endif
- start = format;
+ start = format;
#ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF
{
int res;
char *tmp;
-
+
size = 128;
do {
size *= 2;
@@ -128,7 +128,7 @@
#else
{
char tmp[2];
-
+
/* libce Solarisa przy buforze NULL zawsze zwracaj± -1, wiêc
* musimy podaæ co¶ istniej±cego jako cel printf()owania. */
size = vsnprintf(tmp, sizeof(tmp), format, ap);
@@ -138,7 +138,7 @@
#endif
format = start;
-
+
#ifdef __GG_LIBGADU_HAVE_VA_COPY
vsnprintf(buf, size + 1, format, aq);
va_end(aq);
@@ -150,7 +150,7 @@
vsnprintf(buf, size + 1, format, ap);
# endif
#endif
-
+
return buf;
}
@@ -180,36 +180,36 @@
/*
* gg_get_line() // funkcja pomocnicza
- *
+ *
* podaje kolejn± liniê z bufora tekstowego. niszczy go bezpowrotnie, dziel±c
* na kolejne stringi. zdarza siê, nie ma potrzeby pisania funkcji dubluj±cej
* bufor ¿eby tylko mieæ nieruszone dane wej¶ciowe, skoro i tak nie bêd± nam
* po¼niej potrzebne. obcina `\r\n'.
- *
+ *
* - ptr - wska¼nik do zmiennej, która przechowuje aktualn± pozycjê
* w przemiatanym buforze
- *
+ *
* wska¼nik do kolejnej linii tekstu lub NULL, je¶li to ju¿ koniec bufora.
*/
char *gg_get_line(char **ptr)
{
- char *foo, *res;
+ char *foo, *res;
- if (!ptr || !*ptr || !strcmp(*ptr, ""))
- return NULL;
+ if (!ptr || !*ptr || !strcmp(*ptr, ""))
+ return NULL;
- res = *ptr;
+ res = *ptr;
- if (!(foo = strchr(*ptr, '\n')))
- *ptr += strlen(*ptr);
- else {
- *ptr = foo + 1;
- *foo = 0;
- if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
- res[strlen(res) - 1] = 0;
- }
+ if (!(foo = strchr(*ptr, '\n')))
+ *ptr += strlen(*ptr);
+ else {
+ *ptr = foo + 1;
+ *foo = 0;
+ if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
+ res[strlen(res) - 1] = 0;
+ }
- return res;
+ return res;
}
/*
@@ -227,27 +227,27 @@
*/
int gg_connect(void *addr, int port, int async)
{
- int sock, one = 1;
+ int sock, one = 1, errno2;
struct sockaddr_in sin;
struct in_addr *a = addr;
- struct sockaddr_in myaddr;
+ struct sockaddr_in myaddr;
gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
-
+
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
return -1;
}
- memset(&myaddr, 0, sizeof(myaddr));
- myaddr.sin_family = AF_INET;
+ memset(&myaddr, 0, sizeof(myaddr));
+ myaddr.sin_family = AF_INET;
- myaddr.sin_addr.s_addr = gg_local_ip;
+ myaddr.sin_addr.s_addr = gg_local_ip;
- if(bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
- return -1;
- }
+ if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
+ gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
+ return -1;
+ }
#ifdef ASSIGN_SOCKETS_TO_THREADS
gg_win32_thread_socket(0, sock);
@@ -260,7 +260,9 @@
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
#endif
gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
+ errno2 = errno;
close(sock);
+ errno = errno2;
return -1;
}
}
@@ -268,16 +270,18 @@
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = a->s_addr;
-
+
if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
if (errno && (!async || errno != EINPROGRESS)) {
gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
+ errno2 = errno;
close(sock);
+ errno = errno2;
return -1;
}
gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
}
-
+
return sock;
}
@@ -290,12 +294,16 @@
* - buf - wska¼nik do bufora
* - length - d³ugo¶æ bufora
*
- * je¶li trafi na b³±d odczytu, zwraca NULL. inaczej zwraca buf.
+ * je¶li trafi na b³±d odczytu lub podano nieprawid³owe parametry, zwraca NULL.
+ * inaczej zwraca buf.
*/
char *gg_read_line(int sock, char *buf, int length)
{
int ret;
+ if (!buf || length < 0)
+ return NULL;
+
for (; length > 1; buf++, length--) {
do {
if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) {
@@ -328,13 +336,17 @@
*/
void gg_chomp(char *line)
{
- if (!line || strlen(line) < 1)
+ int len;
+
+ if (!line)
return;
- if (line[strlen(line) - 1] == '\n')
- line[strlen(line) - 1] = 0;
- if (line[strlen(line) - 1] == '\r')
- line[strlen(line) - 1] = 0;
+ len = strlen(line);
+
+ if (len > 0 && line[len - 1] == '\n')
+ line[--len] = 0;
+ if (len > 0 && line[len - 1] == '\r')
+ line[--len] = 0;
}
/*
@@ -352,10 +364,10 @@
{
char *q, *buf, hex[] = "0123456789abcdef";
const char *p;
- int size = 0;
+ unsigned int size = 0;
- if (!str && !(str = strdup("")))
- return NULL;
+ if (!str)
+ str = "";
for (p = str; *p; p++, size++) {
if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-'))
@@ -404,18 +416,18 @@
va_start(ap, format);
for (j = 0; j < strlen(format); j++) {
- unsigned char *arg, buf[16];
+ char *arg, buf[16];
if (format[j] == 'u') {
snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
arg = buf;
} else {
- if (!(arg = va_arg(ap, unsigned char*)))
+ if (!(arg = va_arg(ap, char*)))
arg = "";
- }
+ }
i = 0;
- while ((c = (int) arg[i++]) != 0) {
+ while ((c = (unsigned char) arg[i++]) != 0) {
a = (c ^ b) + (c << 8);
b = (a >> 24) | (a << 8);
}
@@ -446,12 +458,12 @@
int h_errnop, ret;
size_t buflen = 1024;
int new_errno;
-
+
new_errno = ENOMEM;
-
+
if (!(addr = malloc(sizeof(struct in_addr))))
goto cleanup;
-
+
if (!(hp = calloc(1, sizeof(*hp))))
goto cleanup;
@@ -459,45 +471,44 @@
goto cleanup;
tmpbuf = buf;
-
+
while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) {
buflen *= 2;
-
+
if (!(tmpbuf = realloc(buf, buflen)))
break;
-
+
buf = tmpbuf;
}
-
+
if (ret)
new_errno = h_errnop;
if (ret || !hp2 || !tmpbuf)
goto cleanup;
-
+
memcpy(addr, hp->h_addr, sizeof(struct in_addr));
-
+
free(buf);
free(hp);
-
+
return addr;
-
+
cleanup:
errno = new_errno;
-
+
if (addr)
free(addr);
if (hp)
free(hp);
if (buf)
free(buf);
-
+
return NULL;
#else
struct hostent *hp;
if (!(addr = malloc(sizeof(struct in_addr)))) {
- errno = ENOMEM;
goto cleanup;
}
@@ -507,7 +518,7 @@
memcpy(addr, hp->h_addr, sizeof(struct in_addr));
return addr;
-
+
cleanup:
if (addr)
free(addr);
@@ -535,7 +546,7 @@
* je¶li na win32 przy po³±czeniach synchronicznych zapamiêtamy w jakim
* w±tku uruchomili¶my funkcjê, która siê z czymkolwiek ³±czy, to z osobnego
* w±tku mo¿emy anulowaæ po³±czenie poprzez gg_win32_thread_socket(watek, -1);
- *
+ *
* - thread_id - id w±tku. je¶li jest równe 0, brany jest aktualny w±tek,
* je¶li równe -1, usuwa wpis o podanym sockecie.
* - socket - deskryptor gniazda. je¶li równe 0, zwraca deskryptor gniazda
@@ -552,42 +563,41 @@
if (!thread_id)
thread_id = GetCurrentThreadId();
-
+
while (wsk) {
if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) {
if (close) {
/* socket zostaje usuniety */
- closesocket(wsk->socket);
- *p_wsk = wsk->next;
- free(wsk);
- return 1;
- } else if (!socket) {
+ closesocket(wsk->socket);
+ *p_wsk = wsk->next;
+ free(wsk);
+ return 1;
+ } else if (!socket) {
/* socket zostaje zwrocony */
return wsk->socket;
- } else {
+ } else {
/* socket zostaje ustawiony */
wsk->socket = socket;
return socket;
}
- }
+ }
+ p_wsk = &(wsk->next);
+ wsk = wsk->next;
+ }
- p_wsk = &(wsk->next);
- wsk = wsk->next;
- }
-
- if (close && socket != -1)
+ if (close && socket != -1)
closesocket(socket);
- if (close || !socket)
+ if (close || !socket)
return 0;
+
+ /* Dodaje nowy element */
+ wsk = malloc(sizeof(gg_win32_thread));
+ wsk->id = thread_id;
+ wsk->socket = socket;
+ wsk->next = 0;
+ *p_wsk = wsk;
- /* Dodaje nowy element */
- wsk = malloc(sizeof(gg_win32_thread));
- wsk->id = thread_id;
- wsk->socket = socket;
- wsk->next = 0;
- *p_wsk = wsk;
-
- return socket;
+ return socket;
}
#endif /* ASSIGN_SOCKETS_TO_THREADS */
@@ -607,14 +617,14 @@
char *gg_base64_encode(const char *buf)
{
char *out, *res;
- int i = 0, j = 0, k = 0, len = strlen(buf);
-
+ unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
+
res = out = malloc((len / 3 + 1) * 4 + 2);
if (!res)
return NULL;
-
- while (j < len) {
+
+ while (j <= len) {
switch (i % 4) {
case 0:
k = (buf[j] & 252) >> 2;
@@ -646,9 +656,9 @@
if (i % 4)
for (j = 0; j < 4 - (i % 4); j++, out++)
*out = '=';
-
+
*out = 0;
-
+
return res;
}
@@ -665,11 +675,11 @@
{
char *res, *save, *foo, val;
const char *end;
- int index = 0;
+ unsigned int index = 0;
if (!buf)
return NULL;
-
+
save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
if (!save)
@@ -706,7 +716,7 @@
index %= 4;
}
*res = 0;
-
+
return save;
}
@@ -714,7 +724,7 @@
* gg_proxy_auth() // funkcja wewnêtrzna
*
* tworzy nag³ówek autoryzacji dla proxy.
- *
+ *
* zaalokowany tekst lub NULL, je¶li proxy nie jest w³±czone lub nie wymaga
* autoryzacji.
*/
@@ -722,7 +732,7 @@
{
char *tmp, *enc, *out;
unsigned int tmp_size;
-
+
if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
return NULL;
@@ -735,14 +745,14 @@
free(tmp);
return NULL;
}
-
+
free(tmp);
if (!(out = malloc(strlen(enc) + 40))) {
free(enc);
return NULL;
}
-
+
snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc);
free(enc);
@@ -759,7 +769,7 @@
static void gg_crc32_make_table()
{
uint32_t h = 1;
- int i, j;
+ unsigned int i, j;
memset(gg_crc32_table, 0, sizeof(gg_crc32_table));
@@ -789,6 +799,9 @@
if (!gg_crc32_initialized)
gg_crc32_make_table();
+ if (!buf || len < 0)
+ return crc;
+
crc ^= 0xffffffffL;
while (len--)
Index: kopete/protocols/gadu/libgadu/compat.h
===================================================================
--- kopete/protocols/gadu/libgadu/compat.h (revision 417278)
+++ kopete/protocols/gadu/libgadu/compat.h (working copy)
@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+ * USA.
*/
#ifndef __COMPAT_H
Index: kopete/protocols/gadu/libgadu/dcc.c
===================================================================
--- kopete/protocols/gadu/libgadu/dcc.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/dcc.c (working copy)
@@ -52,9 +52,9 @@
* - buf - bufor z danymi
* - size - rozmiar danych
*/
-static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, int size)
+static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, unsigned int size)
{
- int i;
+ unsigned int i;
gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size);
@@ -92,7 +92,7 @@
* - unix - czas w postaci unixowej
* - filetime - czas w postaci windowsowej
*/
-static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft)
+void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft)
{
#ifdef __GG_LIBGADU_HAVE_LONG_LONG
unsigned long long tmp;
@@ -124,31 +124,48 @@
*/
int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename)
{
+ return gg_dcc_fill_file_info2(d, filename, filename);
+}
+
+/*
+ * gg_dcc_fill_file_info2()
+ *
+ * wype³nia pola struct gg_dcc niezbêdne do wys³ania pliku.
+ *
+ * - d - struktura opisuj±ca po³±czenie DCC
+ * - filename - nazwa pliku
+ * - local_filename - nazwa na lokalnym systemie plików
+ *
+ * 0, -1.
+ */
+int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename)
+{
struct stat st;
const char *name, *ext, *p;
+ unsigned char *q;
int i, j;
-
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info(%p, \"%s\");\n", d, filename);
-
+
+ gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info2(%p, \"%s\", \"%s\");\n", d, filename, local_filename);
+
if (!d || d->type != GG_SESSION_DCC_SEND) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() invalid arguments\n");
+ gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() invalid arguments\n");
errno = EINVAL;
return -1;
}
-
- if (stat(filename, &st) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() stat() failed (%s)\n", strerror(errno));
+
+ if (stat(local_filename, &st) == -1) {
+ gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() stat() failed (%s)\n", strerror(errno));
return -1;
}
if ((st.st_mode & S_IFDIR)) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() that's a directory\n");
+ gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() that's a directory\n");
errno = EINVAL;
return -1;
}
- if ((d->file_fd = open(filename, O_RDONLY)) == -1) {
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() open() failed (%s)\n", strerror(errno));
+ if ((d->file_fd = open(local_filename, O_RDONLY)) == -1) {
+ gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno));
return -1;
}
@@ -160,7 +177,7 @@
gg_dcc_fill_filetime(st.st_atime, d->file_info.atime);
gg_dcc_fill_filetime(st.st_mtime, d->file_info.mtime);
gg_dcc_fill_filetime(st.st_ctime, d->file_info.ctime);
-
+
d->file_info.size = gg_fix32(st.st_size);
d->file_info.mode = gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */
@@ -174,14 +191,40 @@
for (i = 0, p = name; i < 8 && p < ext; i++, p++)
d->file_info.short_filename[i] = toupper(name[i]);
-
+
+ if (i == 8 && p < ext) {
+ d->file_info.short_filename[6] = '~';
+ d->file_info.short_filename[7] = '1';
+ }
+
if (strlen(ext) > 0) {
for (j = 0; *ext && j < 4; j++, p++)
d->file_info.short_filename[i + j] = toupper(ext[j]);
-
}
- gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename);
+ for (q = d->file_info.short_filename; *q; q++) {
+ if (*q == 185) {
+ *q = 165;
+ } else if (*q == 230) {
+ *q = 198;
+ } else if (*q == 234) {
+ *q = 202;
+ } else if (*q == 179) {
+ *q = 163;
+ } else if (*q == 241) {
+ *q = 209;
+ } else if (*q == 243) {
+ *q = 211;
+ } else if (*q == 156) {
+ *q = 140;
+ } else if (*q == 159) {
+ *q = 143;
+ } else if (*q == 191) {
+ *q = 175;
+ }
+ }
+
+ gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename);
strncpy(d->file_info.filename, name, sizeof(d->file_info.filename) - 1);
return 0;
@@ -346,7 +389,7 @@
{
struct gg_dcc *c;
struct sockaddr_in sin;
- int sock, bound = 0;
+ int sock, bound = 0, errno2;
gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port);
@@ -383,7 +426,9 @@
if (listen(sock, 10)) {
gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno));
+ errno2 = errno;
close(sock);
+ errno = errno2;
return NULL;
}
@@ -431,6 +476,7 @@
gg_debug(GG_DEBUG_FUNCTION, "++ gg_dcc_voice_send(%p, %p, %d);\n", d, buf, length);
if (!d || !buf || length < 0 || d->type != GG_SESSION_DCC_VOICE) {
gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() invalid argument\n");
+ errno = EINVAL;
return -1;
}
@@ -502,7 +548,7 @@
struct gg_event *e;
int foo;
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h);
+ gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h);
if (!h || (h->type != GG_SESSION_DCC && h->type != GG_SESSION_DCC_SOCKET && h->type != GG_SESSION_DCC_SEND && h->type != GG_SESSION_DCC_GET && h->type != GG_SESSION_DCC_VOICE)) {
gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid argument\n");
@@ -862,7 +908,6 @@
e->event.dcc_voice_data.length = h->chunk_size;
h->state = GG_STATE_READING_VOICE_HEADER;
h->voice_buf = NULL;
-
}
h->check = GG_CHECK_READ;
@@ -1058,6 +1103,15 @@
utmp = sizeof(buf);
gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h->offset, h->file_info.size);
+
+ /* koniec pliku? */
+ if (h->file_info.size == 0) {
+ gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof on empty file\n");
+ e->type = GG_EVENT_DCC_DONE;
+
+ return e;
+ }
+
lseek(h->file_fd, h->offset, SEEK_SET);
size = read(h->file_fd, buf, utmp);
@@ -1215,7 +1269,7 @@
*/
void gg_dcc_free(struct gg_dcc *d)
{
- gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d);
+ gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d);
if (!d)
return;
Index: kopete/protocols/gadu/libgadu/pubdir50.c
===================================================================
--- kopete/protocols/gadu/libgadu/pubdir50.c (revision 417278)
+++ kopete/protocols/gadu/libgadu/pubdir50.c (working copy)
@@ -12,10 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser 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.
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
@@ -84,7 +84,7 @@
return 0;
}
-
+
if (!(dupfield = strdup(field))) {
gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n");
free(dupvalue);
@@ -139,7 +139,7 @@
int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq)
{
gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq);
-
+
if (!req) {
gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n");
errno = EFAULT;
@@ -164,7 +164,7 @@
if (!s)
return;
-
+
for (i = 0; i < s->entries_count; i++) {
free(s->entries[i].field);
free(s->entries[i].value);
@@ -192,7 +192,7 @@
struct gg_pubdir50_request *r;
gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req);
-
+
if (!sess || !req) {
gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n");
errno = EFAULT;
@@ -209,7 +209,7 @@
/* wyszukiwanie bierze tylko pierwszy wpis */
if (req->entries[i].num)
continue;
-
+
size += strlen(req->entries[i].field) + 1;
size += strlen(req->entries[i].value) + 1;
}
@@ -261,12 +261,12 @@
struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet;
gg_pubdir50_t res;
int num = 0;
-
+
gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply(%p, %p, %d);\n", e, packet, length);
if (!e || !packet) {
gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n");
- errno = EINVAL;
+ errno = EFAULT;
return -1;
}
@@ -318,7 +318,7 @@
}
value = NULL;
-
+
for (p = field; p < end; p++) {
/* je¶li mamy koniec tekstu... */
if (!*p) {
@@ -333,7 +333,7 @@
break;
}
}
-
+
/* sprawd¼my, czy pole nie wychodzi poza pakiet, ¿eby nie
* mieæ segfaultów, je¶li serwer przestanie zakañczaæ pakietów
* przez \0 */
@@ -354,10 +354,10 @@
if (gg_pubdir50_add_n(res, num, field, value) == -1)
goto failure;
}
- }
+ }
res->count = num + 1;
-
+
return 0;
failure: