| |
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| |
2 |
| |
3 /* |
| |
4 * $Id: filesession.c 2096 2001-07-31 01:00:39Z warmenhoven $ |
| |
5 * |
| |
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and |
| |
7 * Bill Soudan <soudan@kde.org> |
| |
8 * |
| |
9 * This program is free software; you can redistribute it and/or modify |
| |
10 * it under the terms of the GNU General Public License as published by |
| |
11 * the Free Software Foundation; either version 2 of the License, or |
| |
12 * (at your option) any later version. |
| |
13 * |
| |
14 * This program is distributed in the hope that it will be useful, |
| |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
17 * GNU General Public License for more details. |
| |
18 * |
| |
19 * You should have received a copy of the GNU General Public License |
| |
20 * along with this program; if not, write to the Free Software |
| |
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
22 * |
| |
23 */ |
| |
24 |
| |
25 #include <stdlib.h> |
| |
26 #include <fcntl.h> |
| |
27 #include <sys/stat.h> |
| |
28 |
| |
29 #ifdef _MSVC_ |
| |
30 #include <io.h> |
| |
31 #define open _open |
| |
32 #define close _close |
| |
33 #define read _read |
| |
34 #define write _write |
| |
35 #endif |
| |
36 |
| |
37 #include "icqlib.h" |
| |
38 #include "filesession.h" |
| |
39 #include "stdpackets.h" |
| |
40 |
| |
41 icq_FileSession *icq_FileSessionNew(icq_Link *icqlink) |
| |
42 { |
| |
43 icq_FileSession *p=(icq_FileSession *)malloc(sizeof(icq_FileSession)); |
| |
44 |
| |
45 if (p) |
| |
46 { |
| |
47 p->status=0; |
| |
48 p->id=0L; |
| |
49 p->icqlink=icqlink; |
| |
50 p->tcplink=NULL; |
| |
51 p->current_fd=-1; |
| |
52 p->current_file_num=0; |
| |
53 p->current_file_progress=0; |
| |
54 p->current_file_size=0; |
| |
55 p->files=0L; |
| |
56 p->current_speed=100; |
| |
57 p->total_bytes=0; |
| |
58 p->total_files=0; |
| |
59 p->total_transferred_bytes=0; |
| |
60 p->working_dir[0]=0; |
| |
61 p->user_data=NULL; |
| |
62 icq_ListInsert(icqlink->d->icq_FileSessions, 0, p); |
| |
63 } |
| |
64 |
| |
65 return p; |
| |
66 } |
| |
67 |
| |
68 void icq_FileSessionDelete(void *pv) |
| |
69 { |
| |
70 icq_FileSession *p=(icq_FileSession *)pv; |
| |
71 |
| |
72 invoke_callback(p->icqlink, icq_FileNotify)(p, FILE_NOTIFY_CLOSE, 0, |
| |
73 NULL); |
| |
74 |
| |
75 if(p->files) { |
| |
76 char **p2=p->files; |
| |
77 while(*p2) |
| |
78 free(*(p2++)); |
| |
79 free(p->files); |
| |
80 p->files=NULL; |
| |
81 } |
| |
82 |
| |
83 if (p->current_fd > -1 ) { |
| |
84 close(p->current_fd); |
| |
85 p->current_fd=-1; |
| |
86 } |
| |
87 |
| |
88 free(p); |
| |
89 } |
| |
90 |
| |
91 int _icq_FindFileSession(void *p, va_list data) |
| |
92 { |
| |
93 icq_FileSession *psession=(icq_FileSession *)p; |
| |
94 DWORD uin=va_arg(data, DWORD); |
| |
95 unsigned long id=va_arg(data, unsigned long); |
| |
96 |
| |
97 return (psession->remote_uin == uin) && ( id ? (psession->id == id) : 1 ); |
| |
98 |
| |
99 } |
| |
100 |
| |
101 icq_FileSession *icq_FindFileSession(icq_Link *icqlink, DWORD uin, |
| |
102 unsigned long id) |
| |
103 { |
| |
104 return icq_ListTraverse(icqlink->d->icq_FileSessions, _icq_FindFileSession, |
| |
105 uin, id); |
| |
106 } |
| |
107 |
| |
108 void icq_FileSessionSetStatus(icq_FileSession *p, int status) |
| |
109 { |
| |
110 if(status!=p->status) |
| |
111 { |
| |
112 p->status=status; |
| |
113 if(p->id) |
| |
114 invoke_callback(p->icqlink, icq_FileNotify)(p, FILE_NOTIFY_STATUS, |
| |
115 status, NULL); |
| |
116 if (status == FILE_STATUS_SENDING) |
| |
117 icq_SocketSetHandler(p->tcplink->socket, ICQ_SOCKET_WRITE, |
| |
118 icq_FileSessionSendData, p); |
| |
119 else |
| |
120 icq_SocketSetHandler(p->tcplink->socket, ICQ_SOCKET_WRITE, NULL, NULL); |
| |
121 } |
| |
122 } |
| |
123 |
| |
124 void icq_FileSessionSetHandle(icq_FileSession *p, const char *handle) |
| |
125 { |
| |
126 strncpy(p->remote_handle, handle, 64); |
| |
127 } |
| |
128 |
| |
129 void icq_FileSessionSetCurrentFile(icq_FileSession *p, const char *filename) |
| |
130 { |
| |
131 #ifdef _WIN32 |
| |
132 struct _stat file_status; |
| |
133 #else |
| |
134 struct stat file_status; |
| |
135 #endif |
| |
136 char file[1024]; |
| |
137 |
| |
138 strcpy(file, p->working_dir); |
| |
139 strcat(file, filename); |
| |
140 |
| |
141 if (p->current_fd>-1) { |
| |
142 close(p->current_fd); |
| |
143 p->current_fd=-1; |
| |
144 } |
| |
145 |
| |
146 strncpy(p->current_file, file, 64); |
| |
147 p->current_file_progress=0; |
| |
148 |
| |
149 /* does the file already exist? */ |
| |
150 #ifdef _WIN32 |
| |
151 if (_stat(file, &file_status)==0) { |
| |
152 #else |
| |
153 if (stat(file, &file_status)==0) { |
| |
154 #endif |
| |
155 p->current_file_progress=file_status.st_size; |
| |
156 p->total_transferred_bytes+=file_status.st_size; |
| |
157 #ifdef _WIN32 |
| |
158 p->current_fd=open(file, _O_WRONLY | _O_APPEND | _O_BINARY); |
| |
159 #else |
| |
160 p->current_fd=open(file, O_WRONLY | O_APPEND); |
| |
161 #endif |
| |
162 } else { |
| |
163 #ifdef _WIN32 |
| |
164 p->current_fd=open(file, _O_WRONLY | _O_CREAT | _O_BINARY, |
| |
165 _S_IREAD|_S_IWRITE); |
| |
166 #else |
| |
167 p->current_fd=open(file, O_WRONLY | O_CREAT, S_IRWXU); |
| |
168 #endif |
| |
169 } |
| |
170 |
| |
171 /* make sure we have a valid filehandle */ |
| |
172 if (p->current_fd == -1) |
| |
173 perror("couldn't open file: "); |
| |
174 |
| |
175 } |
| |
176 |
| |
177 void icq_FileSessionPrepareNextFile(icq_FileSession *p) |
| |
178 { |
| |
179 int i=0; |
| |
180 char **files=p->files; |
| |
181 |
| |
182 p->current_file_num++; |
| |
183 |
| |
184 while(*files) { |
| |
185 i++; |
| |
186 if(i==p->current_file_num) |
| |
187 break; |
| |
188 else |
| |
189 files++; |
| |
190 } |
| |
191 |
| |
192 if(*files) { |
| |
193 #ifdef _WIN32 |
| |
194 struct _stat file_status; |
| |
195 #else |
| |
196 struct stat file_status; |
| |
197 #endif |
| |
198 |
| |
199 if (p->current_fd>-1) { |
| |
200 close(p->current_fd); |
| |
201 p->current_fd=-1; |
| |
202 } |
| |
203 |
| |
204 #ifdef _WIN32 |
| |
205 if (_stat(*files, &file_status)==0) { |
| |
206 char *basename=*files; |
| |
207 char *pos=strrchr(basename, '\\'); |
| |
208 #else |
| |
209 if (stat(*files, &file_status)==0) { |
| |
210 char *basename=*files; |
| |
211 char *pos=strrchr(basename, '/'); |
| |
212 #endif |
| |
213 if(pos) basename=pos+1; |
| |
214 strncpy(p->current_file, basename, 64); |
| |
215 p->current_file_progress=0; |
| |
216 p->current_file_size=file_status.st_size; |
| |
217 #ifdef _WIN32 |
| |
218 p->current_fd=open(*files, _O_RDONLY | _O_BINARY); |
| |
219 #else |
| |
220 p->current_fd=open(*files, O_RDONLY); |
| |
221 #endif |
| |
222 } |
| |
223 |
| |
224 /* make sure we have a valid filehandle */ |
| |
225 if (p->current_fd == -1) |
| |
226 perror("couldn't open file: "); |
| |
227 } |
| |
228 } |
| |
229 |
| |
230 void icq_FileSessionSendData(icq_FileSession *p) |
| |
231 { |
| |
232 /* for now just send a packet at a time */ |
| |
233 char buffer[2048]; |
| |
234 int count=read(p->current_fd, buffer, 2048); |
| |
235 |
| |
236 if(count>0) { |
| |
237 icq_Packet *p2=icq_TCPCreateFile06Packet(count, buffer); |
| |
238 icq_TCPLinkSend(p->tcplink, p2); |
| |
239 p->total_transferred_bytes+=count; |
| |
240 p->current_file_progress+=count; |
| |
241 icq_FileSessionSetStatus(p, FILE_STATUS_SENDING); |
| |
242 |
| |
243 invoke_callback(p->icqlink, icq_FileNotify)(p, FILE_NOTIFY_DATAPACKET, |
| |
244 count, buffer); |
| |
245 } |
| |
246 |
| |
247 /* done transmitting if read returns less that 2048 bytes */ |
| |
248 if(count<2048) |
| |
249 icq_FileSessionClose(p); |
| |
250 |
| |
251 return; |
| |
252 } |
| |
253 |
| |
254 /* public */ |
| |
255 |
| |
256 void icq_FileSessionSetSpeed(icq_FileSession *p, int speed) |
| |
257 { |
| |
258 icq_Packet *packet=icq_TCPCreateFile05Packet(speed); |
| |
259 |
| |
260 icq_TCPLinkSend(p->tcplink, packet); |
| |
261 } |
| |
262 |
| |
263 void icq_FileSessionClose(icq_FileSession *p) |
| |
264 { |
| |
265 icq_TCPLink *plink=p->tcplink; |
| |
266 |
| |
267 /* TODO: handle closing already unallocated filesession? */ |
| |
268 |
| |
269 /* if we're attached to a tcplink, unattach so the link doesn't try |
| |
270 * to close us, and then close the tcplink */ |
| |
271 if (plink) |
| |
272 { |
| |
273 plink->session=0L; |
| |
274 icq_TCPLinkClose(plink); |
| |
275 } |
| |
276 |
| |
277 icq_ListRemove(p->icqlink->d->icq_FileSessions, p); |
| |
278 icq_FileSessionDelete(p); |
| |
279 } |
| |
280 |
| |
281 void icq_FileSessionSetWorkingDir(icq_FileSession *p, const char *dir) |
| |
282 { |
| |
283 int length = sizeof(p->working_dir); |
| |
284 strncpy(p->working_dir, dir, length); |
| |
285 p->working_dir[length-1]='\0'; |
| |
286 } |
| |
287 |
| |
288 void icq_FileSessionSetFiles(icq_FileSession *p, char **files) |
| |
289 { |
| |
290 p->files=files; |
| |
291 } |
| |
292 |