1 /***************************************************************************
2 * copyright : (C) 2002 by Hendrik Sattler *
3 * mail : post@hendrik-sattler.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 ***************************************************************************/
11
12 #include "scmxx.h"
13 #include "helper.h"
14 #include "options.h"
15 #include "atcommand.h"
16 #include "ttyaccess.h"
17 #include "gtincl.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <stdio.h>
24
file_transfer_manage(int action,char ** files,char * outfile,char * pipe,char * mem,int slot)25 void file_transfer_manage (int action, char** files,
26 char* outfile, char* pipe,
27 char* mem, int slot)
28 {
29 char* filename;
30 size_t fn_size;
31 struct slot_range** range;
32 struct slot_range** drange; //for free slot detection
33 int enable_search = 1;
34 int i = 0;
35 int j = 0;
36 int k = 0;
37 int current;
38
39 if (mem == NULL) {
40 errexit ("%s\n",_("You must define a memory to use."));
41 }
42 if (strcmp(mem,"?") == 0) {
43 file_print_memlist(NULL,1);
44 return;
45 }
46
47 if (action == 0) {
48 errexit ("%s\n",_("You must specify a valid action."));
49 }
50
51 if (slot < SCMXX_SLOT_BINARY_MIN &&
52 slot != SCMXX_SLOT_UNDEFINED &&
53 slot != SCMXX_SLOT_ALL) {
54 errexit ("%s\n",_("You must define either a valid slot, nothing or \"all\"."));
55 }
56
57 range = file_types_get(action);
58 if (range == NULL || range[0] == NULL) {
59 errexit("%s\n",_("this phone does not support file exchange."));
60 }
61 while (range[i] != NULL &&
62 strcmp(range[i]->name,mem)) {
63 ++i;
64 }
65 if (range[i] == NULL) {
66 errexit("type %s is not supported.\n",mem);
67 }
68 if (slot >= SCMXX_SLOT_BINARY_MIN &&
69 (range[i]->min > slot || slot > range[i]->max)) { // ... test if slot is correctly set
70 if (range[i]->min != range[i]->max) {
71 errexit(_("%s values can only be %d to %d.\n"),range[i]->name,range[i]->min,range[i]->max);
72 } else {
73 errexit(_("%s value can only be %d.\n"),range[i]->name,range[i]->min);
74 }
75 }
76
77 switch(action){
78 default:
79 errexit("%s\n",_("You must specify exactly one operation."));
80 break;
81 case SCMXX_ACTION_REMOVE: //deleting
82 if (slot == SCMXX_SLOT_ALL) {
83 for (current=range[i]->min;current<=range[i]->max;current++) {
84 file_delete(mem, current);
85 }
86 } else if (slot < SCMXX_SLOT_BINARY_MIN) {
87 errexit ("%s\n",_("You must define a valid slot or \"all\"."));
88 } else {
89 file_delete(mem, slot);
90 }
91 break;
92 case SCMXX_ACTION_SEND: //sending
93 if (slot != SCMXX_SLOT_ALL) {
94 // get the detection range (read, not write)...
95 drange = file_types_get(SCMXX_ACTION_SEND);
96 // ...find the mem type in it...
97 while (drange[j] != NULL &&
98 strcmp(drange[j]->name,mem)) {
99 ++j;
100 }
101 if (drange[j] == NULL) {
102 // ...and either disable searching if not found...
103 enable_search = 0;
104 mem_realloc(drange,0);
105 drange = range;
106 j = i;
107 } else {
108 // ...or mak min/max a subrange of both ranges
109 if (drange[j]->min < range[i]->min) {
110 drange[j]->min = range[i]->min;
111 }
112 if (drange[j]->max > range[i]->max) {
113 drange[j]->max = range[i]->max;
114 }
115 }
116 } else {
117 drange = range;
118 j = i;
119 }
120
121 // define current slot...
122 if (slot < range[i]->min) {
123 current = range[i]->min; // ...to minimum if below...
124 } else {
125 current = slot; // ...or the defined slot
126 }
127 while (files[k] != NULL && current <= range[i]->max) {
128 print_verbose(0,_("Using slot %d\n"),current);
129 file_send(files[k],mem,current);
130 if (k == 0) {
131 if (enable_search == 0 && slot != SCMXX_SLOT_ALL) {
132 //stop here if we cannot search for free slots
133 break;
134 } else {
135 //make sure that current is in searchable range
136 if (current < drange[j]->min) {
137 current = drange[j]->min;
138 }
139 }
140 }
141 ++k;
142 if (files[k] != NULL) {
143 if (slot == SCMXX_SLOT_ALL) {
144 ++current; // simply increase if all slot shall be used
145 } else {
146 // only empty slots shall be used
147 current = file_detect_free_slot(mem,current,drange[j]->max);
148 if (current < 0) {
149 errexit("%s\n",_("No free slot found."));
150 } else {
151 print_verbose(0,_("Detected empty slot %d\n"),current);
152 }
153 }
154 }
155 }
156 break;
157 case SCMXX_ACTION_GET: //getting
158 if (slot == SCMXX_SLOT_UNDEFINED) {
159 slot = SCMXX_SLOT_ALL;
160 }
161 if (slot == SCMXX_SLOT_ALL) {
162 fn_size = str_len(outfile)+numlen(range[i]->max)+1+strlen(mem);
163 for (k=range[i]->min;k<=range[i]->max;k++) {
164 if (outfile != NULL) {
165 if (!strcmp(outfile,"-")) {
166 file_get(outfile,pipe,mem,k,k-range[i]->min+1,range[i]->max-range[i]->min+1);
167 } else {
168 filename = mem_alloc(fn_size+1,1);
169 snprintf(filename,fn_size+1,"%s%0*d.%s",
170 outfile,numlen(range[i]->max),k,mem);
171 file_get(filename,pipe,mem,k,k-range[i]->min+1,range[i]->max-range[i]->min+1);
172 free(filename);
173 }
174 } else {
175 errexit("%s\n",_("You must specify a file name prefix (can be \"\")."));
176 }
177 }
178 } else {
179 i = 0;
180 k = 1;
181 file_get(outfile,pipe,mem,slot,i,k);
182 }
183 fprintf(stderr,"\n");
184 break;
185 }
186 }
187
file_delete(char * ftype,int slot)188 void file_delete (char* ftype, int slot) {
189 char* ausgabe;
190
191 if (at_sie_binary_write(ftype,slot,0,0) == NULL) return;
192 ausgabe = at_read_line();
193 if (!strcmp(ausgabe,"OK")) {
194 print_verbose(0,_("%s %d deleted.\n"),ftype,slot);
195 } else {
196 errexit(_("%s %d NOT deleted, something went wrong: %s\n"),ftype,slot,ausgabe);
197 }
198 mem_realloc(ausgabe,0);
199 }
200
file_detect_free_slot(char * ftype,int minimum,int maximum)201 int file_detect_free_slot (char* ftype, int minimum, int maximum) {
202 char* ausgabe;
203 char* content;
204 int i;
205 enum return_code status;
206
207 print_verbose(0,"%s\n",_("Trying to find an empty slot..."));
208 i = minimum;
209 while (i <= maximum) {
210 if (at_sie_binary_read(ftype,i) == NULL) break;
211 ausgabe = at_read_line();
212 status = at_line_type(ausgabe,AT_SIE_BIN_READ,&content);
213 switch (status) {
214 case AT_RET_ERROR_CME:
215 if (strcmp(content,"unknown")) errexit("%s\n",content);
216 /* no break */
217 case AT_RET_OK:
218 mem_realloc(ausgabe,0);
219 return i;
220 case AT_RET_ERROR:
221 errexit("%s\n",_("unknown cause"));
222 case AT_RET_ERROR_CMS:
223 errexit("%s\n",content);
224 default:
225 do {
226 mem_realloc(ausgabe,0);
227 ausgabe = at_read_line();
228 status = at_line_type(ausgabe,AT_SIE_BIN_READ,&content);
229 } while (status == AT_RET_ANSWER ||
230 status == AT_RET_OTHER);
231 if (status == AT_RET_OK) {
232 ++i;
233 } else if (status == AT_RET_ERROR) {
234 errexit("%s\n",_("unknown cause"));
235 } else {
236 errexit("%s\n",content);
237 }
238 mem_realloc(ausgabe,0);
239 break;
240 //no break
241 }
242 }
243 return -1;
244 }
245
246 /* these are just for documenting the
247 * paket size limits
248 */
249 #define FILE_PDUSIZE_MAX_SPEC 176 //max as in spec
250 #define FILE_PDUSIZE_MAX_SL42 175 //max for SL42 v23
251 #define FILE_PDUSIZE_MIN_S45 6 //min for S45/ME45 v10
252
253 #define FILE_PDUSIZE 175
254
file_send(char * file,char * ftype,int slot)255 void file_send (char* file, char* ftype, int slot) {
256 char* data;
257 unsigned int count = file_read_binary(file,&data);
258
259 unsigned int pcount = (count/FILE_PDUSIZE);
260 unsigned int i = 1;
261 unsigned int k;
262 unsigned int psize = FILE_PDUSIZE;
263 char buffer[(FILE_PDUSIZE*2)+1];
264 char* ack;
265 char* vendor = at_get_vendor();
266 char* model = at_get_model();
267 unsigned int strategy = 0;
268
269 if (count%FILE_PDUSIZE) ++pcount;
270
271 /* we need different stategies here
272 * 0: equal packet size except last packet (S55)
273 * 1: try to split the last two packets equally (S45/ME45)
274 * It does not matter for other models, see above for default.
275 */
276 if (strcasecmp(vendor,"SIEMENS") == 0 &&
277 (strcasecmp(model,"C45") == 0 || /* not sure if needed but works with this mode */
278 strcasecmp(model,"ME45") == 0 ||
279 strcasecmp(model,"S45") == 0 ||
280 strcasecmp(model,"S45i") == 0)) {
281 strategy = 1;
282 }
283 mem_realloc(vendor,0);
284 mem_realloc(model,0);
285
286 print_verbose(0,"%s\n",_("File transfer..."));
287 for (; i <= pcount; ++i) {
288 /* split the transfer size between the last two packets
289 * make the first one bigger
290 */
291 switch (strategy) {
292 default:
293 case 0:
294 if (psize > count) psize = count;
295 break;
296 case 1:
297 if (count < 2*FILE_PDUSIZE && count > FILE_PDUSIZE)
298 psize = count/2 + (count%2); /* second last packet */
299 else if (count < FILE_PDUSIZE)
300 psize = count; /* last packet */
301 break;
302 }
303
304 /* filling buffer */
305 memset(buffer,0,sizeof(buffer));
306 for (k = 0; k < psize; ++k) {
307 sprintf(buffer+(k*2),"%02x",((uint8_t*)data)[k]&0xFF);
308 }
309 data += k;
310 count -= k;
311
312 //starting packet transfer
313 if (at_sie_binary_write(ftype,slot,i,pcount) == NULL) return;
314 print_verbose(0,"%s",_("Waiting for data request..."));
315 ack = at_read_line();
316
317 if (strncmp(ack,"> ",2) != 0) {
318 if (strcmp(ack,"+CME ERROR: INVALID INDEX") == 0) {
319 print_verbose(0,"%s\n",_("Packet buffer seems to be filled with something else, clearing..."));
320 if (at_sie_binary_write(ftype,slot,-1,-1) == NULL) return;
321 mem_realloc(ack,0);
322 ack = at_read_line();
323 if (strcmp(ack,"OK") != 0)
324 errexit("%s\n",ack);
325 } else {
326 errexit("\n\"%s\"\n",ack);
327 }
328 }
329 mem_realloc(ack,0);
330
331
332 if (verbosity_get()) {
333 print_verbose(1,_("\nSending %d Bytes in packet %d\n"),psize,i);
334 } else {
335 print_verbose(0,"%s",_("Sending data..."));
336 }
337
338 //sending hex data
339 at_data_send(buffer,2*psize);
340 ack = at_read_line();
341 if (strcmp(ack,"OK") == 0) {
342 print_verbose(0,_("Packet %d sent\n"),i);
343 } else if (strcmp(ack,"+CME ERROR: INV CHAR IN TEXT") == 0) {
344 errexit("%s\n",_("Wrong data format"));
345 } else {
346 errexit("\n\"%s\"\n",ack);
347 }
348 mem_realloc(ack,0);
349 }
350 if (pcount) {
351 print_verbose(0,"%s\n",_("File transfer complete."));
352 } else {
353 print_verbose(0,"%s\n",_("Nothing to transfer."));
354 }
355 }
356
file_get(char * file,char * pipe,char * ftype,unsigned long slot,unsigned long count,unsigned long total)357 void file_get (char* file, char* pipe,
358 char* ftype, unsigned long slot,
359 unsigned long count, unsigned long total)
360 {
361 char* ausgabe;
362 char* temp = NULL;
363 char* command;
364 char* parsestr;
365 enum return_code atcode;
366 unsigned long current[2];
367 unsigned long totals[2];
368 int myfd = -1;
369 unsigned int i = 0;
370 unsigned char data;
371 char datastr[3];
372 FILE* pipefd = NULL;
373 char* text;
374 long text_size = console_width(0);
375
376 memset(datastr,0,sizeof(datastr));
377
378 command = at_sie_binary_read(ftype,slot);
379 if (command == NULL) return;
380
381 text = mem_alloc(text_size,1);
382 snprintf(text,text_size,_("%s slot %lu"),ftype,slot);
383 current[0] = 0;
384 totals[0] = 1;
385 current[1] = count;
386 totals[1] = total;
387
388 parsestr = mem_alloc(1+strlen(ftype)+2+numlen(slot)+(2*(strlen(",%d")+1))+1,1);
389 /* example: ^SBNR: "vcf",9,1,3 */
390 sprintf(parsestr,"\"%s\",%lu,%%d,%%d",ftype,slot);
391 do{
392 ausgabe = at_read_line();
393 atcode = at_line_type(ausgabe,command,&temp);
394 //here we have to check not only for an output of OK, but because of
395 //funny behaviour of the S55 and later, also for "+CME ERROR: unknown".
396 //both stand for an empty entry
397 if (atcode == AT_RET_OK ||
398 (atcode == AT_RET_ERROR_CME && strcmp(temp,"unknown") == 0)) {
399 mem_realloc(ausgabe,0);
400 mem_realloc(parsestr,0);
401 ++current[1];
402 console_print_status(STDERR_FILENO,text,strlen(text),current,totals,2);
403 file_close(myfd);
404 return;
405 } else if (atcode&AT_RET_ERROR) {
406 file_close(myfd);
407 errexit("%s\n",(temp)?temp:ausgabe);
408 } else {
409 console_print_status(STDERR_FILENO,text,strlen(text),current,totals,2);
410 if (2 != sscanf(temp,parsestr,¤t[0],&totals[0]))
411 errexit(_("parsing answer from phone failed: \"%s\"\n"),ausgabe);
412 if (str_len(file) && myfd==-1) {
413 myfd=file_open_output(file);
414 }
415 if (str_len(pipe) && pipefd==NULL) {
416 pipefd=popen(pipe,"w");
417 }
418 mem_realloc(ausgabe,0);
419 ausgabe = at_read_line();
420 for (i=0;i<strlen(ausgabe);i+=2) {
421 data=hexstr2int(ausgabe+i,2);
422 if (myfd!=-1) {
423 if (write(myfd,&data,1) == -1) {
424 file_close(myfd);
425 if (str_len(pipe) && pipefd!=NULL) {
426 pclose(pipefd);
427 }
428 errexit(_("writing to file \"%s\" failed: %s\n"),file, strerror(errno));
429 }
430 }
431 if (str_len(pipe) && pipefd!=NULL) {
432 if (fwrite(&data,1,1,pipefd)!=1) {
433 file_close(myfd);
434 pclose(pipefd);
435 errexit(_("writing to pipe \"%s\" failed.\n"),pipe);
436 }
437 }
438 }
439 mem_realloc(ausgabe,0);
440 }
441 } while (current[0] != totals[0]);
442 ++current[1];
443 console_print_status(STDERR_FILENO,text,strlen(text),current,totals,2);
444
445 file_close(myfd);
446 if (str_len(pipe) && pipefd!=NULL && pclose(pipefd)==-1) {
447 file_close(myfd);
448 errexit(_("closing pipe \"%s\" failed.\n"),pipe);
449 }
450 ausgabe = at_read_line();
451 if (at_line_type(ausgabe,NULL,&temp) == AT_RET_OK) {
452 mem_realloc(ausgabe,0);
453 } else {
454 errexit("%s\n",temp);
455 }
456 }
457