2005-07-01 [colin] 1.9.12cvs8
[claws.git] / src / recv.c
index 5aec6ad996ee22debef049597c12bd81d68ca239..67987f64317f2dbfd8c6748863dae8e7cc682b3c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999,2000 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2001 Hiroyuki Yamamoto
  *
  * 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
 #  include "config.h"
 #endif
 
+#include "defs.h"
+
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/time.h>
 
-#include "intl.h"
 #include "recv.h"
 #include "socket.h"
 #include "utils.h"
 
-#define BUFFSIZE       8192
+static RecvUIFunc      recv_ui_func;
+static gpointer                recv_ui_func_data;
 
 gint recv_write_to_file(SockInfo *sock, const gchar *filename)
 {
        FILE *fp;
+       gint ret;
 
        g_return_val_if_fail(filename != NULL, -1);
 
-       if ((fp = fopen(filename, "w")) == NULL) {
+       if ((fp = fopen(filename, "wb")) == NULL) {
                FILE_OP_ERROR(filename, "fopen");
                recv_write(sock, NULL);
                return -1;
@@ -48,10 +53,10 @@ gint recv_write_to_file(SockInfo *sock, const gchar *filename)
        if (change_file_mode_rw(fp, filename) < 0)
                FILE_OP_ERROR(filename, "chmod");
 
-       if (recv_write(sock, fp) < 0) {
+       if ((ret = recv_write(sock, fp)) < 0) {
                fclose(fp);
                unlink(filename);
-               return -1;
+               return ret;
        }
 
        if (fclose(fp) == EOF) {
@@ -66,10 +71,11 @@ gint recv_write_to_file(SockInfo *sock, const gchar *filename)
 gint recv_bytes_write_to_file(SockInfo *sock, glong size, const gchar *filename)
 {
        FILE *fp;
+       gint ret;
 
        g_return_val_if_fail(filename != NULL, -1);
 
-       if ((fp = fopen(filename, "w")) == NULL) {
+       if ((fp = fopen(filename, "wb")) == NULL) {
                FILE_OP_ERROR(filename, "fopen");
                recv_write(sock, NULL);
                return -1;
@@ -78,10 +84,10 @@ gint recv_bytes_write_to_file(SockInfo *sock, glong size, const gchar *filename)
        if (change_file_mode_rw(fp, filename) < 0)
                FILE_OP_ERROR(filename, "chmod");
 
-       if (recv_bytes_write(sock, size, fp) < 0) {
+       if ((ret = recv_bytes_write(sock, size, fp)) < 0) {
                fclose(fp);
                unlink(filename);
-               return -1;
+               return ret;
        }
 
        if (fclose(fp) == EOF) {
@@ -97,41 +103,61 @@ gint recv_write(SockInfo *sock, FILE *fp)
 {
        gchar buf[BUFFSIZE];
        gint len;
-       gboolean nb;
+       gint count = 0;
+       gint bytes = 0;
+       struct timeval tv_prev, tv_cur;
 
-       nb = sock_is_nonblocking_mode(sock);
-       if (nb) sock_set_nonblocking_mode(sock, FALSE);
+       gettimeofday(&tv_prev, NULL);
 
        for (;;) {
-               if (sock_read(sock, buf, sizeof(buf)) < 0) {
-                       g_warning(_("error occurred while retrieving data.\n"));
-                       if (nb) sock_set_nonblocking_mode(sock, TRUE);
-                       return -1;
+               if (sock_gets(sock, buf, sizeof(buf)) < 0) {
+                       g_warning("error occurred while retrieving data.\n");
+                       return -2;
                }
 
                len = strlen(buf);
-               if (len > 1 && buf[0] == '.' && buf[1] == '\r') break;
+               if (len > 1 && buf[0] == '.' && buf[1] == '\r') {
+                       if (recv_ui_func)
+                               recv_ui_func(sock, count, bytes,
+                                            recv_ui_func_data);
+                       break;
+               }
+               count++;
+               bytes += len;
+
+               if (recv_ui_func) {
+                       gettimeofday(&tv_cur, NULL);
+                       /* if elapsed time from previous update is greater
+                          than 50msec, update UI */
+                       if (tv_cur.tv_sec - tv_prev.tv_sec > 0 ||
+                           tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) {
+                               gboolean ret;
+                               ret = recv_ui_func(sock, count, bytes,
+                                                  recv_ui_func_data);
+                               if (ret == FALSE) return -1;
+                               gettimeofday(&tv_prev, NULL);
+                       }
+               }
 
                if (len > 1 && buf[len - 1] == '\n' && buf[len - 2] == '\r') {
                        buf[len - 2] = '\n';
                        buf[len - 1] = '\0';
+                       len--;
                }
 
                if (buf[0] == '.' && buf[1] == '.')
-                       memmove(buf, buf + 1, strlen(buf));
+                       memmove(buf, buf + 1, len--);
 
                if (!strncmp(buf, ">From ", 6))
-                       memmove(buf, buf + 1, strlen(buf));
+                       memmove(buf, buf + 1, len--);
 
                if (fp && fputs(buf, fp) == EOF) {
                        perror("fputs");
-                       g_warning(_("Can't write to file.\n"));
+                       g_warning("Can't write to file.\n");
                        fp = NULL;
                }
        }
 
-       if (nb) sock_set_nonblocking_mode(sock, TRUE);
-
        if (!fp) return -1;
 
        return 0;
@@ -140,50 +166,62 @@ gint recv_write(SockInfo *sock, FILE *fp)
 gint recv_bytes_write(SockInfo *sock, glong size, FILE *fp)
 {
        gchar *buf;
-       gboolean nb;
        glong count = 0;
        gchar *prev, *cur;
 
-       nb = sock_is_nonblocking_mode(sock);
-       if (nb) sock_set_nonblocking_mode(sock, FALSE);
+       if (size == 0)
+               return 0;
 
-       Xalloca(buf, size, return -1);
+       buf = g_malloc(size);
 
        do {
-               size_t read_count;
+               gint read_count;
 
-               /* FIXME: put this into socket.c :WK: */
-               read_count = fd_read(sock->sock, buf + count, size - count);
+               read_count = sock_read(sock, buf + count, size - count);
                if (read_count < 0) {
-                       if (nb) sock_set_nonblocking_mode(sock, TRUE);
-                       return -1;
+                       g_free(buf);
+                       return -2;
                }
                count += read_count;
        } while (count < size);
 
+       /* +------------------+----------------+--------------------------+ *
+        * ^buf               ^prev            ^cur             buf+size-1^ */
+
        prev = buf;
-       while ((cur = memchr(prev, '\r', size)) != NULL) {
-               if (cur - buf + 1 < size && *(cur + 1) == '\n') {
-                       if (fwrite(prev, sizeof(gchar), cur - prev, fp) == EOF ||
-                           fwrite("\n", sizeof(gchar), 1, fp) == EOF) {
-                               perror("fwrite");
-                               g_warning(_("Can't write to file.\n"));
-                               if (nb) sock_set_nonblocking_mode(sock, TRUE);
-                               return -1;
-                       }
-                       prev = cur + 2;
-                       if (prev - buf >= size) break;
+       while ((cur = memchr(prev, '\r', size - (prev - buf))) != NULL) {
+               if (cur == buf + size - 1) break;
+
+               if (fwrite(prev, sizeof(gchar), cur - prev, fp) == EOF ||
+                   fwrite("\n", sizeof(gchar), 1, fp) == EOF) {
+                       perror("fwrite");
+                       g_warning("Can't write to file.\n");
+                       g_free(buf);
+                       return -1;
                }
+
+               if (*(cur + 1) == '\n')
+                       prev = cur + 2;
+               else
+                       prev = cur + 1;
+
+               if (prev - buf >= size) break;
        }
 
        if (prev - buf < size && fwrite(buf, sizeof(gchar),
                                        size - (prev - buf), fp) == EOF) {
                perror("fwrite");
-               g_warning(_("Can't write to file.\n"));
-               if (nb) sock_set_nonblocking_mode(sock, TRUE);
+               g_warning("Can't write to file.\n");
+               g_free(buf);
                return -1;
        }
 
-       if (nb) sock_set_nonblocking_mode(sock, TRUE);
+       g_free(buf);
        return 0;
 }
+
+void recv_set_ui_func(RecvUIFunc func, gpointer data)
+{
+       recv_ui_func = func;
+       recv_ui_func_data = data;
+}