Statistics
| Revision:

root / libsylph / recv.c @ 3039

History | View | Annotate | Download (5 kB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2007 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
40
gchar *recv_bytes(SockInfo *sock, glong size)
41
{
42
        gchar *buf;
43
        glong count = 0;
44
45
        if (size == 0)
46
                return NULL;
47
48
        buf = g_malloc(size + 1);
49
50
        do {
51
                gint read_count;
52
53
                read_count = sock_read(sock, buf + count,
54
                                       MIN(BUFFSIZE, size - count));
55
                if (read_count <= 0) {
56
                        g_free(buf);
57
                        return NULL;
58
                }
59
                count += read_count;
60
        } while (count < size);
61
62
        buf[size] = '\0';
63
64
        return buf;
65
}
66
67
gint recv_write_to_file(SockInfo *sock, const gchar *filename)
68
{
69
        FILE *fp;
70
        gint ret;
71
72
        g_return_val_if_fail(filename != NULL, -1);
73
74
        if ((fp = g_fopen(filename, "wb")) == NULL) {
75
                FILE_OP_ERROR(filename, "fopen");
76
                recv_write(sock, NULL);
77
                return -1;
78
        }
79
80
        if (change_file_mode_rw(fp, filename) < 0)
81
                FILE_OP_ERROR(filename, "chmod");
82
83
        if ((ret = recv_write(sock, fp)) < 0) {
84
                fclose(fp);
85
                g_unlink(filename);
86
                return ret;
87
        }
88
89
        if (fclose(fp) == EOF) {
90
                FILE_OP_ERROR(filename, "fclose");
91
                g_unlink(filename);
92
                return -1;
93
        }
94
95
        return 0;
96
}
97
98
gint recv_bytes_write_to_file(SockInfo *sock, glong size, const gchar *filename)
99
{
100
        FILE *fp;
101
        gint ret;
102
103
        g_return_val_if_fail(filename != NULL, -1);
104
105
        if ((fp = g_fopen(filename, "wb")) == NULL) {
106
                FILE_OP_ERROR(filename, "fopen");
107
                return recv_bytes_write(sock, size, NULL);
108
        }
109
110
        if (change_file_mode_rw(fp, filename) < 0)
111
                FILE_OP_ERROR(filename, "chmod");
112
113
        if ((ret = recv_bytes_write(sock, size, fp)) < 0) {
114
                fclose(fp);
115
                g_unlink(filename);
116
                return ret;
117
        }
118
119
        if (fclose(fp) == EOF) {
120
                FILE_OP_ERROR(filename, "fclose");
121
                g_unlink(filename);
122
                return -1;
123
        }
124
125
        return 0;
126
}
127
128
gint recv_write(SockInfo *sock, FILE *fp)
129
{
130
        gchar buf[BUFFSIZE];
131
        gint len;
132
        gint count = 0;
133
        gint bytes = 0;
134
        gchar *p;
135
        GTimeVal tv_prev, tv_cur;
136
137
        g_get_current_time(&tv_prev);
138
139
        for (;;) {
140
                if (sock_gets(sock, buf, sizeof(buf)) < 0) {
141
                        g_warning(_("error occurred while retrieving data.\n"));
142
                        return -2;
143
                }
144
145
                len = strlen(buf);
146
                if (len > 1 && buf[0] == '.' && buf[1] == '\r') {
147
                        if (recv_ui_func)
148
                                recv_ui_func(sock, count, bytes,
149
                                             recv_ui_func_data);
150
                        break;
151
                }
152
                count++;
153
                bytes += len;
154
155
                if (recv_ui_func) {
156
                        g_get_current_time(&tv_cur);
157
                        /* if elapsed time from previous update is greater
158
                           than 50msec, update UI */
159
                        if (tv_cur.tv_sec - tv_prev.tv_sec > 0 ||
160
                            tv_cur.tv_usec - tv_prev.tv_usec > UI_REFRESH_INTERVAL) {
161
                                gboolean ret;
162
                                ret = recv_ui_func(sock, count, bytes,
163
                                                   recv_ui_func_data);
164
                                if (ret == FALSE) return -1;
165
                                g_get_current_time(&tv_prev);
166
                        }
167
                }
168
169
                p = buf;
170
171
                if (len > 1 && buf[len - 1] == '\n' && buf[len - 2] == '\r') {
172
                        buf[len - 2] = '\n';
173
                        buf[len - 1] = '\0';
174
                }
175
176
                if (buf[0] == '.' && buf[1] == '.')
177
                        p++;
178
                else if (!strncmp(buf, ">From ", 6))
179
                        p++;
180
181
                if (fp && fputs(p, fp) == EOF) {
182
                        perror("fputs");
183
                        g_warning(_("Can't write to file.\n"));
184
                        fp = NULL;
185
                }
186
        }
187
188
        if (!fp) return -1;
189
190
        return 0;
191
}
192
193
gint recv_bytes_write(SockInfo *sock, glong size, FILE *fp)
194
{
195
        gchar *buf;
196
        gchar *prev, *cur;
197
198
        if (size == 0)
199
                return 0;
200
201
        buf = recv_bytes(sock, size);
202
        if (!buf)
203
                return -2;
204
205
        /* +------------------+----------------+--------------------------+ *
206
         * ^buf               ^prev            ^cur             buf+size-1^ */
207
208
        prev = buf;
209
        while ((cur = memchr(prev, '\r', size - (prev - buf))) != NULL) {
210
                if (cur == buf + size - 1) break;
211
212
                if (fp && (fwrite(prev, sizeof(gchar), cur - prev, fp) == EOF ||
213
                           fwrite("\n", sizeof(gchar), 1, fp) == EOF)) {
214
                        perror("fwrite");
215
                        g_warning(_("Can't write to file.\n"));
216
                        fp = NULL;
217
                }
218
219
                if (*(cur + 1) == '\n')
220
                        prev = cur + 2;
221
                else
222
                        prev = cur + 1;
223
224
                if (prev - buf >= size) break;
225
        }
226
227
        if (prev - buf < size && fp &&
228
            fwrite(buf, sizeof(gchar), size - (prev - buf), fp) == EOF) {
229
                perror("fwrite");
230
                g_warning(_("Can't write to file.\n"));
231
                fp = NULL;
232
        }
233
234
        g_free(buf);
235
236
        if (!fp) return -1;
237
238
        return 0;
239
}
240
241
void recv_set_ui_func(RecvUIFunc func, gpointer data)
242
{
243
        recv_ui_func = func;
244
        recv_ui_func_data = data;
245
}