1 /*
2 
3   G N O K I I
4 
5   A Linux/Unix toolset and driver for the mobile phones.
6 
7   This file is part of gnokii.
8 
9   Gnokii 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   Gnokii 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 gnokii; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23   Copyright (C) 1999-2000 Hugh Blemings & Pavel Jan�k ml.
24   Copyright (C) 2000      Jan Derfinak
25   Copyright (C) 2000-2011 Pawel Kot
26   Copyright (C) 2001      Jan Kratochvil, Ladis Michl, Chris Kemp
27   Copyright (C) 2002-2004 BORBELY Zoltan
28   Copyright (C) 2002      Manfred Jonsson, Markus Plail
29 
30   Some parts of the gn_lock_device() function are derived from minicom
31   communications package, main.c file written by Miquel van Smoorenburg.
32   These parts are copyrighted under GNU GPL version 2.
33 
34   Copyright 1991-1995 Miquel van Smoorenburg.
35 
36 */
37 
38 #include "config.h"
39 #include <string.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <signal.h>
46 
47 #include "compat.h"
48 
49 #include "misc.h"
50 #include "gnokii.h"
51 #include "gnokii-internal.h"
52 
53 GNOKII_API gn_log_target gn_log_debug_mask = GN_LOG_T_NONE;
54 GNOKII_API gn_log_target gn_log_rlpdebug_mask = GN_LOG_T_NONE;
55 GNOKII_API gn_log_target gn_log_xdebug_mask = GN_LOG_T_NONE;
56 GNOKII_API void (*gn_elog_handler)(const char *fmt, va_list ap) = NULL;
57 
gn_line_get(FILE * file,char * line,int count)58 GNOKII_API int gn_line_get(FILE *file, char *line, int count)
59 {
60 	char *ptr;
61 
62 	if (fgets(line, count, file)) {
63 		ptr = line + strlen(line) - 1;
64 
65 		while ((*ptr == '\n' || *ptr == '\r') && ptr >= line)
66 			*ptr-- = '\0';
67 
68 		return strlen(line);
69 	} else {
70 		return 0;
71 	}
72 }
73 
74 static gn_phone_model models[] = {
75 	/* model, product_name, ... */
76 	{"2711",  "?????",	PM_OLD_DEFAULT },		/* Dancall */
77 	{"2731",  "?????",	PM_OLD_DEFAULT },
78 	{"11",    "TFF-3",	PM_OLD_DEFAULT },
79 	{"12",    "RX-2",	PM_OLD_DEFAULT },
80 	{"20",    "TME-2",	PM_OLD_DEFAULT },
81 	{"22",    "TME-1",	PM_OLD_DEFAULT },
82 	{"30",    "TME-3",	PM_OLD_DEFAULT },
83 	{"100",   "THX-9L",	PM_OLD_DEFAULT },
84 	{"450",   "THF-9",	PM_OLD_DEFAULT },
85 	{"505",   "NHX-8",	PM_OLD_DEFAULT },
86 	{"540",   "THF-11",	PM_OLD_DEFAULT },
87 	{"550",	  "THF-10",	PM_OLD_DEFAULT },
88 	{"640",   "THF-13",	PM_OLD_DEFAULT },
89 	{"650",   "THF-12",	PM_OLD_DEFAULT },
90 	{"810",   "TFE-4R",	PM_OLD_DEFAULT },
91 	{"1011",  "NHE-2",	PM_OLD_DEFAULT },
92 	{"1100",  "RH-18",	PM_OLD_DEFAULT },
93 	{"1100",  "RH-38",	PM_OLD_DEFAULT },
94 	{"1100b", "RH-36",	PM_OLD_DEFAULT },
95 	{"1101",  "RH-75",	PM_OLD_DEFAULT }, /* Yet another 1100 variant, untested */
96 	{"1110",  "RH-93",	PM_DEFAULT_S30 },
97 	{"1209",  "RH-105",	PM_DEFAULT_S30 },
98 	{"1220",  "NKC-1",	PM_OLD_DEFAULT },
99 	{"1260",  "NKW-1",	PM_OLD_DEFAULT },
100 	{"1261",  "NKW-1C",	PM_OLD_DEFAULT },
101 	{"1280",  "RM-647",	PM_DEFAULT_S30 },
102 	{"1610",  "NHE-5",	PM_OLD_DEFAULT },
103 	{"1610",  "NHE-5NX",	PM_OLD_DEFAULT },
104 	{"1611",  "NHE-5",	PM_OLD_DEFAULT },
105 	{"1630",  "NHE-5NA",	PM_OLD_DEFAULT },
106 	{"1630",  "NHE-5NX",	PM_OLD_DEFAULT },
107 	{"1631",  "NHE-5SA",	PM_OLD_DEFAULT },
108 	{"2010",  "NHE-3",	PM_OLD_DEFAULT },
109 	{"2100",  "NAM-2",	PM_OLD_DEFAULT },
110 	{"2110",  "NHE-1",	PM_OLD_DEFAULT },
111 	{"2110i", "NHE-4",	PM_OLD_DEFAULT },
112 	{"2118",  "NHE-4",	PM_OLD_DEFAULT },
113 	{"2140",  "NHK-1XA",	PM_OLD_DEFAULT },
114 	{"2148",  "NHK-1",	PM_OLD_DEFAULT },
115 	{"2148i", "NHK-4",	PM_OLD_DEFAULT },
116 	{"2160",  "NHC-4NE/HE",	PM_OLD_DEFAULT },
117 	{"2160i", "NHC-4NE/HE",	PM_OLD_DEFAULT },
118 	{"2170",  "NHP-4",	PM_OLD_DEFAULT },
119 	{"2180",  "NHD-4X",	PM_OLD_DEFAULT },
120 	{"2190",  "NHB-3NB",	PM_OLD_DEFAULT },
121 	{"2220",  "RH-40",	PM_OLD_DEFAULT },
122 	{"2220",  "RH-42",	PM_OLD_DEFAULT },
123 	{"2260",  "RH-39",	PM_OLD_DEFAULT },
124 	{"2260",  "RH-41",	PM_OLD_DEFAULT },
125 	{"2270",  "RH-3P",	PM_OLD_DEFAULT },
126 	{"2275",  "RH-3DNG",	PM_OLD_DEFAULT },
127 	{"2280",  "RH-17",	PM_OLD_DEFAULT },
128 	{"2285",  "RH-3",	PM_OLD_DEFAULT },
129 	{"2300",  "RM-4",	PM_OLD_DEFAULT },
130 	{"2300b", "RM-5",	PM_OLD_DEFAULT },
131 	{"2330 classic", "RM-512",	PM_DEFAULT_S40_3RD }, /* Series 40 5th Edition FP 1 Lite */
132 	{"2600",  "RH-59",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
133 	{"2630",  "RM-298",	PM_DEFAULT },
134 	{"2650",  "RH-53",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
135 	{"2700 classic",  "RM-561",	PM_DEFAULT_S40_3RD },
136 	{"2730 classic",  "RM-578",	PM_DEFAULT_S40_3RD }, /* Series 40 5th Edition FP 1 */
137 	{"2760",  "RM-258",	PM_DEFAULT_S40_3RD }, /* Series 40 5th Edition */
138 	{"3100",  "RH-19",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
139 	{"3100b", "RH-50",	PM_DEFAULT },
140 	{"3105",  "RH-48",	PM_OLD_DEFAULT },
141 	{"3108",  "RH-6",	PM_OLD_DEFAULT },
142 	{"3109c", "RM-274",	PM_DEFAULT_S40_3RD }, /* Nokia 3109 classic */
143 	{"3110",  "NHE-8",	PM_OLD_DEFAULT | PM_DATA },
144 	{"3110",  "0310" ,	PM_OLD_DEFAULT | PM_DATA }, /* NHE-8 */
145 	{"3110c", "RM-237",     PM_DEFAULT_S40_3RD }, /* Nokia 3110 classic */
146 	{"3120",  "RH-19",	PM_DEFAULT },
147 	{"3120b", "RH-50",	PM_DEFAULT },
148 	{"3200",  "RH-30",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
149 	{"3200",  "RH-30/31",	PM_DEFAULT },
150 	{"3200b", "RH-31",	PM_DEFAULT },
151 	{"3210",  "NSE-8",	PM_OLD_DEFAULT | PM_NETMONITOR },
152 	{"3210",  "NSE-9",	PM_OLD_DEFAULT },
153 	{"3220",  "RH-37",	PM_DEFAULT },
154 	{"3285",  "NSD-1A",	PM_OLD_DEFAULT },
155 	{"3300",  "NEM-1",	PM_OLD_DEFAULT | PM_XGNOKIIBREAKAGE },
156 	{"3300",  "NEM-2",	PM_OLD_DEFAULT | PM_XGNOKIIBREAKAGE },
157 	{"3310",  "NHM-5",	PM_OLD_DEFAULT | PM_NETMONITOR },
158 	{"3310",  "NHM-5NX",	PM_OLD_DEFAULT },
159 	{"3315",  "NHM-5NY",	PM_OLD_DEFAULT },
160 	{"3320",  "NPC-1",	PM_OLD_DEFAULT },
161 	{"3330",  "NHM-6",	PM_OLD_DEFAULT | PM_NETMONITOR },
162 	{"3350",  "NHM-9",	PM_OLD_DEFAULT },
163 	{"3360",  "NPW-6",	PM_OLD_DEFAULT },
164 	{"3360",  "NPW-1",	PM_OLD_DEFAULT },
165 	{"3361",  "NPW-1",	PM_OLD_DEFAULT },
166 	{"3390",  "NPB-1",	PM_OLD_DEFAULT },
167 	{"3395",  "NPB-1B",	PM_OLD_DEFAULT },
168 	{"3410",  "NHM-2",	PM_OLD_DEFAULT | PM_NETMONITOR },
169 	{"3500c", "RM-272",	PM_DEFAULT },
170 	{"3510",  "NHM-8",	PM_DEFAULT },
171 	{"3510i", "RH-9",	PM_DEFAULT },
172 	{"3520",  "RH-21",	PM_DEFAULT },
173 	{"3530",  "RH-9",	PM_DEFAULT },
174 	{"3560",  "RH-14",	PM_DEFAULT },
175 	{"3570",  "NPD-1FW",	PM_OLD_DEFAULT },
176 	{"3585",  "NPD-1AW",	PM_OLD_DEFAULT },
177 	{"3585i", "NPD-4AW",	PM_OLD_DEFAULT },
178 	{"3586i", "RH-44",	PM_OLD_DEFAULT },
179 	{"3590",  "NPM-8",	PM_OLD_DEFAULT },
180 	{"3595",  "NPM-10",	PM_OLD_DEFAULT },
181 	{"3600",  "NHM-10",	PM_OLD_DEFAULT },
182 	{"3610",  "NAM-1",	PM_OLD_DEFAULT },
183 	{"3620",  "NHM-10X",	PM_OLD_DEFAULT },
184 	{"3650",  "NHL-8",	PM_DEFAULT | PM_NETMONITOR },
185 	{"3660",  "NHL-8X",	PM_DEFAULT | PM_NETMONITOR },
186 	{"3810",  "0305" ,	PM_OLD_DEFAULT | PM_DATA }, /* NHE-9 */
187 	{"3810",  "NHE-9",	PM_OLD_DEFAULT | PM_DATA },
188 	{"5100",  "NPM-6",	PM_DEFAULT },
189 	{"5100",  "NPM-6X",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
190 	{"5100",  "NMP-6",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
191 	{"5110",  "NSE-1",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
192 	{"5110",  "NSE-1NX",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
193 	{"5110i", "NSE-1NY",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
194 	{"5110i", "NSE-2NY",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
195 	{"5120",  "NSC-1",	PM_OLD_DEFAULT  },
196 	{"5125",  "NSC-1",	PM_OLD_DEFAULT },
197 	{"5130",  "NSK-1",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
198 	{"5130 XpressMusic",  "RM-495",	PM_DEFAULT_S40_3RD },
199 	{"5140",  "NPL-5",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
200 	{"5140i", "RM-104",	PM_DEFAULT },
201 	{"5160",  "NSW-1",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
202 	{"5170",  "NSD-1F",	PM_OLD_DEFAULT },
203 	{"5180",  "NSD-1G",	PM_OLD_DEFAULT },
204 	{"5185",  "NSD-1A",	PM_OLD_DEFAULT },
205 	{"5190",  "NSB-1",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
206 	{"5210",  "NSM-5",	PM_DEFAULT },
207 	{"5300 XpressMusic",  "RM-146",	PM_DEFAULT_S40_3RD },
208 	{"5310 XpressMusic",  "RM-303",	PM_DEFAULT_S40_3RD },
209 	{"5510",  "NPM-5",	PM_OLD_DEFAULT },
210 	{"6010",  "NPM-10",	PM_OLD_DEFAULT },
211 	{"6010",  "NPM-10X",	PM_OLD_DEFAULT },
212 	{"6011",  "RTE-2RH",	PM_OLD_DEFAULT },
213 	{"6015i", "RH-55",	PM_DEFAULT },
214 	{"6020",  "RM-30",	PM_DEFAULT },
215 	{"6021",  "RM-94",	PM_DEFAULT | PM_XGNOKIIBREAKAGE},
216 	{"6030",  "RM-74",      PM_DEFAULT },
217 	{"6050",  "NME-1",	PM_OLD_DEFAULT },
218 	{"6070",  "RM-166",	PM_DEFAULT },
219 	{"6080",  "NME-2",	PM_OLD_DEFAULT },
220 	{"6081",  "NME-2A",	PM_OLD_DEFAULT },
221 	{"6081",  "NME-2E",	PM_OLD_DEFAULT },
222 	{"6085",  "RM-260",     PM_DEFAULT },
223 	{"6090",  "NME-3",	PM_OLD_DEFAULT },
224 	{"6100",  "NPL-2",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
225 	{"6108",  "RH-4",	PM_OLD_DEFAULT },
226 	{"6110",  "NSE-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
227 	{"6120",  "NSC-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
228 	{"6130",  "NSK-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
229 	{"6133",  "RM-126",	PM_DEFAULT_S40_3RD },
230 	{"6136",  "RM-199",	PM_DEFAULT | PM_FULLPBK },
231 	{"6138",  "NSK-3",	PM_OLD_DEFAULT },
232 	{"6150",  "NSM-1",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
233 	{"616x",  "NSW-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
234 	{"6160",  "NSW-3AX",	PM_OLD_DEFAULT },
235 	{"6161",  "NSW-3ND",	PM_OLD_DEFAULT },
236 	{"6162",  "NSW-3AF",	PM_OLD_DEFAULT },
237 	{"6170",  "RM47_-48",	PM_DEFAULT },
238 	{"6185",  "NSD-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
239 	{"6185i", "NSD-3AW",	PM_OLD_DEFAULT },
240 	{"6188",  "NSD-3AX",	PM_OLD_DEFAULT },
241 	{"6190",  "NSB-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA | PM_AUTHENTICATION },
242 	{"6200",  "NPL-3",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
243 	{"6210",  "NPE-3",	PM_DEFAULT | PM_NETMONITOR },
244 	{"6220",  "RH-20",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
245 	{"6225",  "RH-27",	PM_OLD_DEFAULT },
246 	{"6230",  "RH-12_28_-",	PM_DEFAULT },
247 	{"6230",  "RH12_28_-",	PM_DEFAULT },
248 	{"6230i", "RM72_73_-",	PM_DEFAULT },
249 	{"6233",  "RM123_145_-", PM_DEFAULT },
250 	{"6250",  "NHM-3",	PM_DEFAULT | PM_NETMONITOR },
251 	{"6280",  "RH-78",	PM_DEFAULT },
252 	{"6300",  "RM-217",     PM_DEFAULT_S40_3RD | PM_FULLPBK },
253 	{"6303",  "RM-443",     PM_DEFAULT_S40_3RD | PM_FULLPBK }, /* Nokia 6303 classic */
254 	{"6310",  "NPE-4",	PM_DEFAULT },
255 	{"6310i", "NPL-1",	PM_DEFAULT },
256 	{"6340",  "NPM-2",	PM_OLD_DEFAULT },
257 	{"6340i", "RH-13",	PM_OLD_DEFAULT },
258 	{"6360",  "NPW-2",	PM_DEFAULT },
259 	{"6370",  "NHP-2FX",	PM_OLD_DEFAULT },
260 	{"6385",  "NHP-2AX",	PM_OLD_DEFAULT },
261 	{"6500",  "NHM-7",	PM_DEFAULT },
262 	{"6500c", "RM-265",	PM_DEFAULT_S40_3RD | PM_FULLPBK }, /* Series 40 5th Edition */
263 	{"6510",  "NPM-9",	PM_DEFAULT },
264 	{"6560",  "RH-25",	PM_OLD_DEFAULT },
265 	{"6585",  "RH-34",	PM_OLD_DEFAULT },
266 	{"6590",  "NSM-9",	PM_OLD_DEFAULT },
267 	{"6590i", "NSM-9",	PM_OLD_DEFAULT },
268 	{"6600",  "NHL-10",	PM_DEFAULT | PM_NETMONITOR },
269 	{"6610",  "NHL-4U",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
270 	{"6610i", "RM-37",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
271 	{"6650",  "NHM-1",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
272 	{"6680",  "RM-36",	PM_DEFAULT },
273 	{"6700 classic",  "RM-470",	PM_DEFAULT_S40_3RD },  /* Series 40 6th Edition */
274 	{"6800",  "NHL-6",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
275 	{"6800",  "NSB-9",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
276 	{"6810",  "RM-2",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
277 	{"6820",  "NHL-9",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
278 	{"6820b", "RH-26",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
279 	{"6822",  "RM-69",	PM_DEFAULT },
280 	{"7110",  "NSE-5",	PM_DEFAULT | PM_NETMONITOR },
281 	{"7160",  "NSW-5",	PM_OLD_DEFAULT },
282 	{"7190",  "NSB-5",	PM_DEFAULT | PM_NETMONITOR },
283 	{"7200",  "RH-23",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
284 	{"7210",  "NHL-4",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
285 	{"7250",  "NHL-4J",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
286 	{"7250i", "NHL-4JX",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
287 	{"7260",  "RM-17",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
288 	{"7270",  "RM-8",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
289 	{"7280",  "RM-14",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
290 	{"7373",  "RM-209",	PM_DEFAULT },
291 	{"7600",  "NMM-3",	PM_DEFAULT | PM_XGNOKIIBREAKAGE },
292 	{"7650",  "NHL-2NA",	PM_DEFAULT },
293 	{"8110",  "0423" ,	PM_OLD_DEFAULT | PM_DATA }, /* NHE-6BX */
294 	{"8110",  "2501",	PM_OLD_DEFAULT | PM_DATA },
295 	{"8110",  "NHE-6",	PM_OLD_DEFAULT | PM_DATA },
296 	{"8110",  "NHE-6BX",	PM_OLD_DEFAULT | PM_DATA },
297 	{"8110i", "0423",	PM_OLD_DEFAULT | PM_DATA }, /* Guess for NHE-6 */
298 	{"8110i", "NHE-6",	PM_OLD_DEFAULT | PM_DATA },
299 	{"8110i", "NHE-6BM",	PM_OLD_DEFAULT | PM_DATA },
300 	{"8146",  "NHK-6",	PM_OLD_DEFAULT | PM_DATA },
301 	{"8148",  "NHK-6",	PM_OLD_DEFAULT | PM_DATA },
302 	{"8148i", "NHK-6V",	PM_OLD_DEFAULT | PM_DATA },
303 	{"8210",  "NSM-3",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA },
304 	{"8250",  "NSM-3D",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA },
305 	{"8260",  "NSW-4",	PM_OLD_DEFAULT },
306 	{"8265",  "NPW-3",	PM_OLD_DEFAULT },
307 	{"8270",  "NSD-5FX",	PM_OLD_DEFAULT },
308 	{"8280",  "RH-10",	PM_OLD_DEFAULT },
309 	{"8290",  "NSB-7",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA },
310 	{"8310",  "NHM-7",	PM_DEFAULT  },
311 	{"8390",  "NSB-8",	PM_OLD_DEFAULT },
312 	{"8810",  "NSE-6",	PM_OLD_DEFAULT | PM_DATA },
313 	{"8850",  "NSM-2",	PM_OLD_DEFAULT | PM_NETMONITOR | PM_DATA },
314 	{"8855",  "NSM-4",	PM_OLD_DEFAULT },
315 	{"8860",  "NSW-6",	PM_OLD_DEFAULT },
316 	{"8890",  "NSB-6",	PM_OLD_DEFAULT },
317 	{"8910",  "NHM-4NX",	PM_OLD_DEFAULT },
318 	{"8910i", "NHM-4NX",	PM_OLD_DEFAULT },
319 	{"9000",  "RAE-1",	PM_OLD_DEFAULT },
320 	{"9000i", "RAE-4",	PM_OLD_DEFAULT },
321 	{"9110",  "RAE-2",	PM_OLD_DEFAULT },
322 	{"9110i", "RAE-2i",	PM_OLD_DEFAULT },
323 	{"9210",  "RAE-2",	PM_OLD_DEFAULT },
324 	{"9210c", "RAE-3",	PM_OLD_DEFAULT },
325 	{"9210i", "RAE-5N",	PM_OLD_DEFAULT },
326 	{"9290",  "RAE-3N",	PM_OLD_DEFAULT },
327 	{"N70",   "RM-84",      PM_DEFAULT },
328 	{"N73",   "RM-133",	PM_DEFAULT },
329 	{"RPM-1", "RPM-1",	PM_OLD_DEFAULT | PM_DATA },
330 	{"C1-01", "RM-607",	PM_DEFAULT_S40_3RD },  /* Series 40 6th Edition Lite */
331 	{"C2-03", "RM-70",	PM_DEFAULT_S40_3RD },
332 	{"Card Phone 1.0", "RPE-1",	PM_OLD_DEFAULT | PM_DATA },
333 	{"Card Phone 2.0", "RPM-1",	PM_OLD_DEFAULT | PM_DATA },
334 	{"C110 Wireless LAN Card", "DTN-10",	PM_OLD_DEFAULT },
335 	{"C111 Wireless LAN Card", "DTN-11",	PM_OLD_DEFAULT },
336 	{"D211",  "DTE-1",	PM_OLD_DEFAULT },
337 	{"N-Gage", "NEM-4",	PM_OLD_DEFAULT },
338 	{"RinGo", "NHX-7",	PM_OLD_DEFAULT },
339 	{"sx1",  "SX1",		PM_DEFAULT },
340 	{"SIM/USIM", "APDU",	0 },
341 	{NULL,    NULL, 0 } /* keep last one as NULL */
342 };
343 
344 #define MODELS_NUM_ENTRIES (sizeof(models)/sizeof(models[0]))
345 
346 /* this should be in libfunctions - will move it there with next version of libgnokii */
gn_lib_get_supported_phone_model(const int num)347 GNOKII_API const char *gn_lib_get_supported_phone_model( const int num )
348 {
349 	if (num < 0 || num >= MODELS_NUM_ENTRIES)
350 		return NULL;
351 	return models[num].model;
352 }
353 
354 
gn_phone_model_get(const char * product_name)355 GNOKII_API gn_phone_model *gn_phone_model_get(const char *product_name)
356 {
357 	int i = 0;
358 
359 	while (models[i].product_name != NULL) {
360 		if (strcmp(product_name, models[i].product_name) == 0) {
361 			dprintf("Found model \"%s\"\n", product_name);
362 			return (&models[i]);
363 		}
364 		i++;
365 	}
366 
367 	return (&models[MODELS_NUM_ENTRIES-1]); /* NULL entry */
368 }
369 
gn_model_get(const char * product_name)370 GNOKII_API const char *gn_model_get(const char *product_name)
371 {
372 	return gn_cfg_get_phone_model(gn_cfg_info, product_name)->model;
373 }
374 
log_printf(gn_log_target mask,const char * fmt,va_list ap)375 static void log_printf(gn_log_target mask, const char *fmt, va_list ap)
376 {
377 	if (mask & GN_LOG_T_STDERR) {
378 		vfprintf(stderr, fmt, ap);
379 		fflush(stderr);
380 	}
381 }
382 
gn_log_debug(const char * fmt,...)383 GNOKII_API void gn_log_debug(const char *fmt, ...)
384 {
385 #ifdef DEBUG
386 	va_list ap;
387 
388 	va_start(ap, fmt);
389 
390 	log_printf(gn_log_debug_mask, fmt, ap);
391 
392 	va_end(ap);
393 #endif
394 }
395 
gn_log_rlpdebug(const char * fmt,...)396 GNOKII_API void gn_log_rlpdebug(const char *fmt, ...)
397 {
398 #ifdef RLP_DEBUG
399 	va_list ap;
400 
401 	va_start(ap, fmt);
402 
403 	log_printf(gn_log_rlpdebug_mask, fmt, ap);
404 
405 	va_end(ap);
406 #endif
407 }
408 
gn_log_xdebug(const char * fmt,...)409 GNOKII_API void gn_log_xdebug(const char *fmt, ...)
410 {
411 #ifdef XDEBUG
412 	va_list ap;
413 
414 	va_start(ap, fmt);
415 
416 	log_printf(gn_log_xdebug_mask, fmt, ap);
417 
418 	va_end(ap);
419 #endif
420 }
421 
gn_elog_write(const char * fmt,...)422 GNOKII_API void gn_elog_write(const char *fmt, ...)
423 {
424 	va_list ap, ap1;
425 
426 	va_start(ap, fmt);
427 
428 	va_copy(ap1, ap);
429 	log_printf(gn_log_debug_mask, fmt, ap1);
430 	va_end(ap1);
431 
432 	if (gn_elog_handler) {
433 		va_copy(ap1, ap);
434 		gn_elog_handler(fmt, ap1);
435 		va_end(ap1);
436 	} else {
437 #ifndef	DEBUG
438 		if (!(gn_log_debug_mask & GN_LOG_T_STDERR)) {
439 			va_copy(ap1, ap);
440 			log_printf(GN_LOG_T_STDERR, fmt, ap1);
441 			va_end(ap1);
442 		}
443 #endif
444 	}
445 
446 	va_end(ap);
447 }
448 
449 #define BUFFER_MAX_LENGTH 128
450 #if defined (__svr4__)
451 #  define lock_path "/var/run/LCK.."
452 #else
453 #  define lock_path "/var/lock/LCK.."
454 #endif
455 
456 /* Lock the device. Return allocated string with a lock name */
gn_device_lock(const char * port)457 GNOKII_API char *gn_device_lock(const char* port)
458 {
459 #ifndef WIN32
460 	char *lock_file = NULL;
461 	char buffer[BUFFER_MAX_LENGTH];
462 	const char *aux = strrchr(port, '/');
463 	int fd, len;
464 
465 	if (!port) {
466 		fprintf(stderr, _("Cannot lock NULL device. Set port config parameter correctly.\n"));
467 		return NULL;
468 	}
469 
470 	/* Remove leading '/' */
471 	if (aux)
472 		aux++;
473 	else
474 		aux = port;
475 
476 	len = strlen(aux) + strlen(lock_path);
477 
478 	memset(buffer, 0, sizeof(buffer));
479 	lock_file = calloc(len + 1, 1);
480 	if (!lock_file) {
481 		fprintf(stderr, _("Out of memory error while locking device.\n"));
482 		return NULL;
483 	}
484 	/*
485 	 * I think we don't need to use strncpy, as we should have enough
486 	 * buffer due to strlen results, but it's safer to do so...
487 	 */
488 	strncpy(lock_file, lock_path, len);
489 	strncat(lock_file, aux, len - strlen(lock_file));
490 
491 	/* Check for the stale lockfile.
492 	 * The code taken from minicom by Miquel van Smoorenburg */
493 	if ((fd = open(lock_file, O_RDONLY)) >= 0) {
494 		char buf[BUFFER_MAX_LENGTH];
495 		int pid, n = 0;
496 
497 		n = read(fd, buf, sizeof(buf) - 1);
498 		close(fd);
499 		if (n > 0) {
500 			pid = -1;
501 			if (n == 4)
502 				/* Kermit-style lockfile. */
503 				pid = *(int *)buf;
504 			else {
505 				/* Ascii lockfile. */
506 				buf[n] = 0;
507 				sscanf(buf, "%d", &pid);
508 			}
509 			if (pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH) {
510 				fprintf(stderr, _("Lockfile %s is stale. Overriding it...\n"), lock_file);
511 				sleep(1);
512 				if (unlink(lock_file) == -1) {
513 					fprintf(stderr, _("Overriding file %s failed, please check the permissions.\n"), lock_file);
514 					fprintf(stderr, _("Cannot lock device.\n"));
515 					goto failed;
516 				}
517 			} else {
518 				fprintf(stderr, _("Device already locked with %s.\n"), lock_file);
519 				goto failed;
520 			}
521 		}
522 		/* This must not happen. Because we could open the file    */
523 		/* no wrong permissions are set. Only reason could be      */
524 		/* flock/lockf or an empty lockfile due to a broken binary */
525 		/* which is more likely (like gnokii 0.4.0pre11 ;-).       */
526 		if (n == 0) {
527 			fprintf(stderr, _("Unable to read lockfile %s.\n"), lock_file);
528 			fprintf(stderr, _("Please check for reason and remove the lockfile by hand.\n"));
529 			fprintf(stderr, _("Cannot lock device.\n"));
530 			goto failed;
531 		}
532 	}
533 
534 	/* Try to create a new file, with 0644 mode */
535 	fd = open(lock_file, O_CREAT | O_EXCL | O_WRONLY, 0644);
536 	if (fd == -1) {
537 		if (errno == EEXIST)
538 			fprintf(stderr, _("Device seems to be locked by unknown process.\n"));
539 		else if (errno == EACCES)
540 			fprintf(stderr, _("Please check permission on lock directory.\n"));
541 		else if (errno == ENOENT)
542 			fprintf(stderr, _("Cannot create lockfile %s. Please check for existence of the path.\n"), lock_file);
543 		goto failed;
544 	}
545 	snprintf(buffer, sizeof(buffer), "%10ld gnokii\n", (long)getpid());
546 	if (write(fd, buffer, strlen(buffer)) < 0) {
547 		fprintf(stderr, _("Failed to write to the lockfile %s.\n"), lock_file);
548 		goto failed;
549 	}
550 	close(fd);
551 	return lock_file;
552 failed:
553 	if (fd > -1)
554 		close(fd);
555 	free(lock_file);
556 	return NULL;
557 #else
558 	return (char *)1;
559 #endif /* WIN32 */
560 }
561 
562 /* Removes lock and frees memory */
gn_device_unlock(char * lock_file)563 GNOKII_API int gn_device_unlock(char *lock_file)
564 {
565 #ifndef WIN32
566 	int err;
567 
568 	if (lock_file) {
569 		err = unlink(lock_file);
570 		free(lock_file);
571 		if (err) {
572 			fprintf(stderr, _("Cannot unlock device: %s\n"), strerror(errno));
573 			return false;
574 		}
575 	}
576 	return true;
577 #else
578 	return true;
579 #endif /* WIN32 */
580 }
581 
582 /*
583  * Splits string into NULL-terminated string array
584  */
gnokii_strsplit(const char * string,const char * delimiter,int tokens)585 char **gnokii_strsplit(const char *string, const char *delimiter, int tokens)
586 {
587 	const char *left = string;
588 	char *tmp, *str;
589 	int count = 0;
590 	char **strings;
591 
592 	if (!string || !delimiter || !tokens)
593 		return NULL;
594 
595 	/*
596 	 * Last two elements are:
597 	 *  - leftover from the input line
598 	 *  - NULL (required by gnokii_strfreev())
599 	 */
600 	strings = calloc(tokens + 2, sizeof(char *));
601 
602 	while ((tmp = strstr(left, delimiter)) != NULL && (count < tokens)) {
603 		str = malloc((tmp - left) + 1);
604 		memset(str, 0, (tmp - left) + 1);
605 		memcpy(str, left, tmp - left);
606 		strings[count] = str;
607 		left = tmp + strlen(delimiter);
608 		count++;
609 	}
610 
611 	strings[count] = strdup(left);
612 	/*
613 	 * Make NULL termination explicit even if it is done via calloc().
614 	 * gnokii_strfreev() requires it to be NULL-terminated.
615 	 */
616 	strings[count + 1] = NULL;
617 
618 	for (count = 0; count < tokens; count++) {
619 		dprintf("strings[%d] = %s\n", count, strings[count]);
620 	}
621 
622 	return strings;
623 }
624 
625 /*
626  * frees NULL-terminated array of strings
627  */
gnokii_strfreev(char ** str_array)628 void gnokii_strfreev(char **str_array)
629 {
630 	char **tmp = str_array;
631 
632 	if (!str_array)
633 		return;
634 
635 	while (*tmp) {
636 		free(*tmp);
637 		tmp++;
638 	}
639 	free(str_array);
640 }
641 
642 /**
643  * gnokii_strcmpsep:
644  * @s1: a string, NUL terminated, may NOT contain @sep
645  * @s2: a string, NUL terminated, may contain @sep
646  * @sep: comparison stops if this char is found in @s2
647  *
648  * Returns: < 0 if @s1 < @s2
649  *            0 if @s1 == @s2
650  *          > 0 if @s1 > @s2
651  *
652  * Compares two strings up to a NUL terminator or a separator char.
653  * Leading and trailing white space in @s2 is ignored.
654  */
gnokii_strcmpsep(const char * s1,const char * s2,char sep)655 int gnokii_strcmpsep(const char *s1, const char *s2, char sep)
656 {
657 	while (isspace(*s2))
658 		s2++;
659 	while (*s1 && *s1 == *s2) {
660 		s1++;
661 		s2++;
662 	}
663 	while (isspace(*s2))
664 		s2++;
665 	if (!*s1 && *s2 == sep)
666 		return 0;
667 
668 	return *s1 - *s2;
669 }
670 
671 /*
672  * check if the timestamp in dt has valid date and time
673  */
gn_timestamp_isvalid(const gn_timestamp dt)674 GNOKII_API int gn_timestamp_isvalid(const gn_timestamp dt)
675 {
676 #define BETWEEN(a, x, y)	((a >= x) && (a <= y))
677 	int daynum;
678 
679 	/* assume that year is OK */
680 	switch (dt.month) {
681 	case 2:
682 		if (((dt.year % 4) == 0) &&
683 		    (((dt.year % 100) != 0) ||
684 		     ((dt.year % 1000) == 0)))
685 			daynum = 29;
686 		else
687 			daynum = 28;
688 		break;
689 	case 1:
690 	case 3:
691 	case 5:
692 	case 7:
693 	case 8:
694 	case 10:
695 	case 12:
696 		daynum = 31;
697 		break;
698 	default:
699 		daynum = 30;
700 		break;
701 	}
702 	return (BETWEEN(dt.month, 1, 12) && BETWEEN(dt.day, 1, daynum) &&
703 		BETWEEN(dt.hour, 0, 24) && BETWEEN(dt.minute, 0, 59) &&
704 		BETWEEN(dt.second, 0, 59));
705 }
706