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,&current[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