Statistics
| Revision:

root / libsylph / recv.c @ 578

History | View | Annotate | Download (4.8 kB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include "defs.h"
25
26
#include <glib.h>
27
#include <glib/gi18n.h>
28
#include <stdio.h>
29
#include <string.h>
30
#include <unistd.h>
31
32
#include "recv.h"
33
#include "socket.h"
34
#include "utils.h"
35
36
static RecvUIFunc        recv_ui_func;
37
static gpointer                recv_ui_func_data;
38
39
gint recv_write_to_file(SockInfo *sock, const gchar *filename)
40
{
41
        FILE *fp;
42
        gint ret;
43
44
        g_return_val_if_fail(filename != NULL, -1);
45
46
        if ((fp = g_fopen(filename, "wb")) == NULL) {
47
                FILE_OP_ERROR(filename, "fopen");
48
                recv_write(sock, NULL);
49
                return -1;
50
        }
51
52
        if (change_file_mode_rw(fp, filename) < 0)
53
                FILE_OP_ERROR(filename, "chmod");
54
55
        if ((ret = recv_write(sock, fp)) < 0) {
56
                fclose(fp);
57
                g_unlink(filename);
58
                return ret;
59
        }
60
61
        if (fclose(fp) == EOF) {
62
                FILE_OP_ERROR(filename, "fclose");
63
                g_unlink(filename);
64
                return -1;
65
        }
66
67
        return 0;
68
}
69
70
gint recv_bytes_write_to_file(SockInfo *sock, glong size, const gchar *filename)
71
{
72
        FILE *fp;
73
        gint ret;
74
75
        g_return_val_if_fail(filename != NULL, -1);
76
77
        if ((fp = g_fopen(filename, "wb")) == NULL) {
78
                FILE_OP_ERROR(filename, "fopen");
79
                return recv_bytes_write(sock, size, NULL);
80
        }
81
82
        if (change_file_mode_rw(fp, filename) < 0)
83
                FILE_OP_ERROR(filename, "chmod");
84
85
        if ((ret = recv_bytes_write(sock, size, fp)) < 0) {
86
                fclose(fp);
87
                g_unlink(filename);
88
                return ret;
89
        }
90
91
        if (fclose(fp) == EOF) {
92
                FILE_OP_ERROR(filename, "fclose");
93
                g_unlink(filename);
94
                return -1;
95
        }
96
97
        return 0;
98
}
99
100
gint recv_write(SockInfo *sock, FILE *fp)
101
{
102
        gchar buf[BUFFSIZE];
103
        gint len;
104
        gint count = 0;
105
        gint bytes = 0;
106
        GTimeVal tv_prev, tv_cur;
107
108
        g_get_current_time(&tv_prev);
109
110
        for (;;) {
111
                if (sock_gets(sock, buf, sizeof(buf)) < 0) {
112
                        g_warning(_("error occurred while retrieving data.\n"));
113
                        return -2;
114
                }
115
116
                len = strlen(buf);
117
                if (len > 1 && buf[0] == '.' && buf[1] == '\r') {
118
                        if (recv_ui_func)
119
                                recv_ui_func(sock, count, bytes,
120
                                             recv_ui_func_data);
121
                        break;
122
                }
123
                count++;
124
                bytes += len;
125
126
                if (recv_ui_func) {
127
                        g_get_current_time(&tv_cur);
128
                        /* if elapsed time from previous update is greater
129
                           than 50msec, update UI */
130
                        if (tv_cur.tv_sec - tv_prev.tv_sec > 0 ||
131
                            tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) {
132
                                gboolean ret;
133
                                ret = recv_ui_func(sock, count, bytes,
134
                                                   recv_ui_func_data);
135
                                if (ret == FALSE) return -1;
136
                                g_get_current_time(&tv_prev);
137
                        }
138
                }
139
140
                if (len > 1 && buf[len - 1] == '\n' && buf[len - 2] == '\r') {
141
                        buf[len - 2] = '\n';
142
                        buf[len - 1] = '\0';
143
                        len--;
144
                }
145
146
                if (buf[0] == '.' && buf[1] == '.')
147
                        memmove(buf, buf + 1, len--);
148
149
                if (!strncmp(buf, ">From ", 6))
150
                        memmove(buf, buf + 1, len--);
151
152
                if (fp && fputs(buf, fp) == EOF) {
153
                        perror("fputs");
154
                        g_warning(_("Can't write to file.\n"));
155
                        fp = NULL;
156
                }
157
        }
158
159
        if (!fp) return -1;
160
161
        return 0;
162
}
163
164
gint recv_bytes_write(SockInfo *sock, glong size, FILE *fp)
165
{
166
        gchar *buf;
167
        glong count = 0;
168
        gchar *prev, *cur;
169
170
        if (size == 0)
171
                return 0;
172
173
        buf = g_malloc(size);
174
175
        do {
176
                gint read_count;
177
178
                read_count = sock_read(sock, buf + count, size - count);
179
                if (read_count < 0) {
180
                        g_free(buf);
181
                        return -2;
182
                }
183
                count += read_count;
184
        } while (count < size);
185
186
        /* +------------------+----------------+--------------------------+ *
187
         * ^buf               ^prev            ^cur             buf+size-1^ */
188
189
        prev = buf;
190
        while ((cur = memchr(prev, '\r', size - (prev - buf))) != NULL) {
191
                if (cur == buf + size - 1) break;
192
193
                if (fp && (fwrite(prev, sizeof(gchar), cur - prev, fp) == EOF ||
194
                           fwrite("\n", sizeof(gchar), 1, fp) == EOF)) {
195
                        perror("fwrite");
196
                        g_warning(_("Can't write to file.\n"));
197
                        fp = NULL;
198
                }
199
200
                if (*(cur + 1) == '\n')
201
                        prev = cur + 2;
202
                else
203
                        prev = cur + 1;
204
205
                if (prev - buf >= size) break;
206
        }
207
208
        if (prev - buf < size && fp &&
209
            fwrite(buf, sizeof(gchar), size - (prev - buf), fp) == EOF) {
210
                perror("fwrite");
211
                g_warning(_("Can't write to file.\n"));
212
                fp = NULL;
213
        }
214
215
        g_free(buf);
216
217
        if (!fp) return -1;
218
219
        return 0;
220
}
221
222
void recv_set_ui_func(RecvUIFunc func, gpointer data)
223
{
224
        recv_ui_func = func;
225
        recv_ui_func_data = data;
226
}