summaryrefslogtreecommitdiff
path: root/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Gadu-Gadu/src/libgadu/handlers.cpp')
-rw-r--r--protocols/Gadu-Gadu/src/libgadu/handlers.cpp103
1 files changed, 78 insertions, 25 deletions
diff --git a/protocols/Gadu-Gadu/src/libgadu/handlers.cpp b/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
index da09c40b5f..3c0018c8c6 100644
--- a/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
+++ b/protocols/Gadu-Gadu/src/libgadu/handlers.cpp
@@ -51,6 +51,7 @@
#include "encoding.h"
#include "message.h"
#include "internal.h"
+#include "deflate.h"
#include <errno.h>
#ifndef _WIN32
@@ -97,6 +98,8 @@ static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, const
int ret;
uint8_t hash_buf[64];
uint32_t local_ip;
+ struct sockaddr_in sin;
+ int sin_len = sizeof(sin);
if (len < sizeof(struct gg_welcome)) {
ge->type = GG_EVENT_CONN_FAILED;
@@ -155,29 +158,22 @@ static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, const
}
#endif
- if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
- struct sockaddr_in sin;
- int sin_len = sizeof(sin);
-
- gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n");
-
- if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
- gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
- local_ip = sin.sin_addr.s_addr;
- } else {
- gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
- local_ip = 0;
- }
- } else
- local_ip = gg_dcc_ip;
-
- gs->client_addr = local_ip;
+ if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
+ gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
+ local_ip = sin.sin_addr.s_addr;
+ } else {
+ gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
+ local_ip = 0;
+ }
if (GG_SESSION_IS_PROTOCOL_8_0(gs)) {
struct gg_login80 l80;
const char *client_name, *version, *descr;
uint32_t client_name_len, version_len, descr_len;
+ if (gs->external_addr == 0)
+ gs->external_addr = local_ip;
+
memset(&l80, 0, sizeof(l80));
gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN80 packet\n");
l80.uin = gg_fix32(gs->uin);
@@ -216,6 +212,11 @@ static int gg_session_handle_welcome(struct gg_session *gs, uint32_t type, const
} else {
struct gg_login70 l70;
+ if (gg_dcc_ip != (unsigned long) inet_addr("255.255.255.255"))
+ local_ip = gg_dcc_ip;
+
+ gs->client_addr = local_ip;
+
memset(&l70, 0, sizeof(l70));
l70.uin = gg_fix32(gs->uin);
l70.hash_type = gs->hash_type;
@@ -777,7 +778,7 @@ malformed:
*
* \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
*/
-static int gg_session_send_msg_ack(struct gg_session *gs)
+static int gg_session_send_msg_ack(struct gg_session *gs, uint32_t seq)
{
struct gg_recv_msg_ack pkt;
@@ -786,8 +787,11 @@ static int gg_session_send_msg_ack(struct gg_session *gs)
if ((gs->protocol_features & GG_FEATURE_MSG_ACK) == 0)
return 0;
+ /* Kiedyś zdawało nam się, że mamy wysyłać liczbę odebranych
+ * wiadomości, ale okazało się, że numer sekwencyjny. */
gs->recv_msg_count++;
- pkt.count = gg_fix32(gs->recv_msg_count);
+
+ pkt.seq = gg_fix32(seq);
return gg_send_packet(gs, GG_RECV_MSG_ACK, &pkt, sizeof(pkt), NULL);
}
@@ -829,7 +833,7 @@ static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, co
switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), options + 1, payload_end)) {
case -1: // handled
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
case -2: // failed
@@ -851,7 +855,7 @@ static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, co
goto fail;
e->event.msg.message = tmp;
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
fail:
@@ -866,7 +870,7 @@ malformed:
free(e->event.msg.xhtml_message);
free(e->event.msg.recipients);
free(e->event.msg.formats);
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
}
@@ -924,7 +928,7 @@ static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type,
if (offset_attr != 0) {
switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), packet + offset_attr, packet + length)) {
case -1: // handled
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
case -2: // failed
@@ -958,7 +962,7 @@ static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type,
else
e->event.msg.xhtml_message = NULL;
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
fail:
@@ -974,7 +978,7 @@ malformed:
free(e->event.msg.xhtml_message);
free(e->event.msg.recipients);
free(e->event.msg.formats);
- gg_session_send_msg_ack(sess);
+ gg_session_send_msg_ack(sess, gg_fix32(r->seq));
return 0;
}
@@ -1705,6 +1709,53 @@ malformed:
}
/**
+ * \internal Obsługuje pakiet GG_USERLIST100_VERSION.
+ *
+ * Patrz gg_packet_handler_t
+ */
+static int gg_session_handle_userlist_100_version(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
+{
+ struct gg_userlist100_version *version = (struct gg_userlist100_version*) ptr;
+
+ gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 version\n");
+
+ ge->type = GG_EVENT_USERLIST100_VERSION;
+ ge->event.userlist100_version.version = gg_fix32(version->version);
+
+ return 0;
+}
+
+/**
+ * \internal Obsługuje pakiet GG_USERLIST100_REPLY.
+ *
+ * Patrz gg_packet_handler_t
+ */
+static int gg_session_handle_userlist_100_reply(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
+{
+ struct gg_userlist100_reply *reply = (struct gg_userlist100_reply*) ptr;
+ char *data = NULL;
+
+ gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 reply\n");
+
+ if (len > sizeof(*reply)) {
+ data = gg_inflate((const unsigned char*) ptr + sizeof(*reply), len - sizeof(*reply));
+
+ if (data == NULL) {
+ gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_userlist_100_reply() gg_inflate() failed\n");
+ return -1;
+ }
+ }
+
+ ge->type = GG_EVENT_USERLIST100_REPLY;
+ ge->event.userlist100_reply.type = reply->type;
+ ge->event.userlist100_reply.version = gg_fix32(reply->version);
+ ge->event.userlist100_reply.format_type = reply->format_type;
+ ge->event.userlist100_reply.reply = data;
+
+ return 0;
+}
+
+/**
* \internal Tablica obsługiwanych pakietów
*/
static const gg_packet_handler_t handlers[] =
@@ -1744,6 +1795,8 @@ static const gg_packet_handler_t handlers[] =
{ GG_MULTILOGON_INFO, GG_STATE_CONNECTED, sizeof(struct gg_multilogon_info), gg_session_handle_multilogon_info },
{ GG_XML_ACTION, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
{ GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
+ { GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version },
+ { GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply },
};
/**