diff libgaim/protocols/qq/sendqueue.c @ 14192:60b1bc8dbf37

[gaim-migrate @ 16863] Renamed 'core' to 'libgaim' committer: Tailor Script <tailor@pidgin.im>
author Evan Schoenberg <evan.s@dreskin.net>
date Sat, 19 Aug 2006 01:50:10 +0000
parents
children 6b8bc59414f0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgaim/protocols/qq/sendqueue.c	Sat Aug 19 01:50:10 2006 +0000
@@ -0,0 +1,223 @@
+/**
+ * The QQ2003C protocol plugin
+ *
+ * for gaim
+ *
+ * Copyright (C) 2004 Puzzlebird
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "connection.h"
+#include "debug.h"
+#include "internal.h"
+#include "notify.h"
+#include "prefs.h"
+#include "request.h"
+
+#include "header_info.h"
+#include "qq_proxy.h"
+#include "sendqueue.h"
+
+#define QQ_RESEND_MAX               5	/* max resend per packet */
+
+typedef struct _gc_and_packet gc_and_packet;
+
+struct _gc_and_packet {
+	GaimConnection *gc;
+	qq_sendpacket *packet;
+};
+
+/* Remove a packet with send_seq from sendqueue */
+void qq_sendqueue_remove(qq_data *qd, guint16 send_seq)
+{
+	GList *list;
+	qq_sendpacket *p;
+
+	g_return_if_fail(qd != NULL);
+
+	list = qd->sendqueue;
+	while (list != NULL) {
+		p = (qq_sendpacket *) (list->data);
+		if (p->send_seq == send_seq) {
+			qd->sendqueue = g_list_remove(qd->sendqueue, p);
+			g_free(p->buf);
+			g_free(p);
+			break;
+		}
+		list = list->next;
+	}
+}
+		
+/* clean up sendqueue and free all contents */
+void qq_sendqueue_free(qq_data *qd)
+{
+	qq_sendpacket *p;
+	gint i;
+
+	i = 0;
+	while (qd->sendqueue != NULL) {
+		p = (qq_sendpacket *) (qd->sendqueue->data);
+		qd->sendqueue = g_list_remove(qd->sendqueue, p);
+		g_free(p->buf);
+		g_free(p);
+		i++;
+	}
+	gaim_debug(GAIM_DEBUG_INFO, "QQ", "%d packets in sendqueue are freed!\n", i);
+}
+
+/* packet lost, agree to send again, (and will NOT prompt again)
+ * it is removed only when ack-ed by server */
+static void _qq_send_again(gc_and_packet *gp)
+{
+	GaimConnection *gc;
+	qq_data *qd;
+	qq_sendpacket *packet;
+	GList *list;
+
+	g_return_if_fail(gp != NULL && gp->gc != NULL && gp->packet != NULL);
+	g_return_if_fail(gp->gc->proto_data != NULL);
+
+	gc = gp->gc;
+	packet = gp->packet;
+	qd = (qq_data *) gc->proto_data;
+
+	list = g_list_find(qd->sendqueue, packet);
+	if (list != NULL) {
+		packet->resend_times = 0;
+		packet->sendtime = time(NULL);
+		qq_proxy_write(qd, packet->buf, packet->len);
+	}
+	g_free(gp);
+}
+
+/* packet lost, do not send again */
+static void _qq_send_cancel(gc_and_packet *gp)
+{
+	GaimConnection *gc;
+	qq_data *qd;
+	qq_sendpacket *packet;
+	GList *list;
+
+	g_return_if_fail(gp != NULL && gp->gc != NULL && gp->packet != NULL);
+	g_return_if_fail(gp->gc->proto_data != NULL);
+
+	gc = gp->gc;
+	packet = gp->packet;
+	qd = (qq_data *) gc->proto_data;
+
+	list = g_list_find(qd->sendqueue, packet);
+	if (list != NULL)
+		qq_sendqueue_remove(qd, packet->send_seq);
+
+	g_free(gp);
+}
+
+gboolean qq_sendqueue_timeout_callback(gpointer data)
+{
+	GaimConnection *gc;
+	qq_data *qd;
+	GList *list;
+	qq_sendpacket *p;
+	gc_and_packet *gp;
+	time_t now;
+	gint wait_time;
+	gboolean need_action;
+
+	gc = (GaimConnection *) data;
+	qd = (qq_data *) gc->proto_data;
+	now = time(NULL);
+	list = qd->sendqueue;
+
+	/* empty queue, return TRUE so that timeout continues functioning */
+	if (qd->sendqueue == NULL)
+		return TRUE;
+
+	while (list != NULL) {	/* remove all packet whose resend_times == -1 */
+		p = (qq_sendpacket *) list->data;
+		if (p->resend_times == -1) {	/* to remove */
+			qd->sendqueue = g_list_remove(qd->sendqueue, p);
+			g_free(p->buf);
+			g_free(p);
+			list = qd->sendqueue;
+		} else {
+			list = list->next;
+		}
+	}
+
+	list = qd->sendqueue;
+	while (list != NULL) {
+		p = (qq_sendpacket *) list->data;
+		if (p->resend_times >= QQ_RESEND_MAX) {
+			if (p->resend_times == QQ_RESEND_MAX) {	/* reach max */
+				switch (p->cmd) {
+				case QQ_CMD_KEEP_ALIVE:
+					if (qd->logged_in) {
+						gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Connection lost!\n");
+						gaim_connection_error(gc, _("Connection lost!"));
+						qd->logged_in = FALSE;
+					}
+					p->resend_times = -1;
+					break;
+				case QQ_CMD_LOGIN:
+					if (!qd->logged_in)	/* cancel logging progress */
+						gaim_connection_error(gc, _("Login failed, no reply!"));
+					p->resend_times = -1;
+					break;
+				case QQ_CMD_UPDATE_INFO:
+					gaim_notify_error(gc, NULL,
+							  _("Connection timeout!"), _("User info is not updated"));
+					p->resend_times = -1;
+					break;
+				default:{
+						need_action =
+						    gaim_prefs_get_bool("/plugins/prpl/qq/prompt_for_missing_packet");
+						if (!need_action)
+							p->resend_times = -1;	/* it will be removed next time */
+						else {	/* prompt for action */
+							gp = g_new0(gc_and_packet, 1);
+							gp->gc = gc;
+							gp->packet = p;
+							gaim_request_action
+							    (gc, NULL,
+							     _
+							     ("Send packet"),
+							     _
+							     ("Packets lost, send again?"),
+							     0, gp, 2,
+							     _("Send"),
+							     G_CALLBACK
+							     (_qq_send_again),
+							     _("Cancel"), G_CALLBACK(_qq_send_cancel));
+							/* will send once more, but only once */
+							p->resend_times++;
+						}
+					}
+				}
+			}
+		} else {	/* resend_times < QQ_RESEND_MAX, so sent it again */
+			wait_time = (gint) (QQ_SENDQUEUE_TIMEOUT / 1000);
+			if (difftime(now, p->sendtime) > (wait_time * (p->resend_times + 1))) {
+				qq_proxy_write(qd, p->buf, p->len);
+				p->resend_times++;
+				gaim_debug(GAIM_DEBUG_INFO,
+					   "QQ", "<<< [%05d] send again for %d times!\n", 
+					   p->send_seq, p->resend_times);
+			}
+		}
+		list = list->next;
+	}
+	return TRUE;		/* if we return FALSE, the timeout callback stops functioning */
+}