1 /***************************************************************************
2                           wxutil.cpp  -  description
3                              -------------------
4     begin                : Thu Aug 14 2003
5     copyright            : (C) 2003 by ARRL
6     author               : Jon Bloom
7     email                : jbloom@arrl.org
8     revision             : $Id$
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "sysconfig.h"
13 #endif
14 
15 #include "wxutil.h"
16 #include <wx/dir.h>
17 #include <wx/config.h>
18 #include <wx/filename.h>
19 #include "tqsllib.h"
20 #include "tqslerrno.h"
21 
22 wxSize
getTextSize(wxWindow * win)23 getTextSize(wxWindow *win) {
24 	wxClientDC dc(win);
25 	wxCoord char_width, char_height;
26 	dc.GetTextExtent(wxString(wxT("M")), &char_width, &char_height);
27 	return wxSize(char_width, char_height);
28 }
29 
30 // isspace() called on extended chars in UTF-8 raises asserts in
31 // the windows C++ libs. Don't call isspace() if out of range.
32 
isspc(int c)33 static inline int isspc(int c) {
34 	if (c < 0 || c > 255)
35 		return 0;
36 	return isspace(c);
37 }
38 
39 wxString
wrapString(wxWindow * win,wxString in,int length)40 wrapString(wxWindow *win, wxString in, int length) {
41 	wxClientDC dc(win);
42 	wxCoord textwidth, textheight;
43 	wxString out = wxT("");
44 	wxString str = in;
45 	do {
46 		dc.GetTextExtent(str, &textwidth, &textheight);
47 		if (textwidth > length) {
48 			int index = 0;
49 				do {
50 					str = str.Left(str.Length()-1);
51 					index++;
52 					dc.GetTextExtent(str, &textwidth, &textheight);
53 
54 					wxString c = wxString(str.Last());
55 
56 					if (textwidth < length && isspc(c[0]))
57 						break;
58 				} while (1);
59 			if (out != wxT(""))
60 				out += wxT("\n");
61 			out += str;
62 			str = in.Right(index);
63 		} else {
64 			break;
65 		}
66 	} while (1);
67 	if (out != wxT(""))
68 		out += wxT("\n");
69 	out += str;
70 	return out;
71 }
72 
73 // Strip special characters from a string prior to writing to XML
74 wxString
urlEncode(wxString & str)75 urlEncode(wxString& str) {
76 	str.Replace(wxT("&"), wxT("&amp;"), true);
77 	str.Replace(wxT("\""), wxT("&quot;"), true);
78 	str.Replace(wxT("'"), wxT("&apos;"), true);
79 	str.Replace(wxT("<"), wxT("&lt;"), true);
80 	str.Replace(wxT(">"), wxT("&gt;"), true);
81 	return str;
82 }
83 
84 // Convert UTF-8 string to UCS-2 (MS Unicode default)
85 int
utf8_to_ucs2(const char * in,char * out,size_t buflen)86 utf8_to_ucs2(const char *in, char *out, size_t buflen) {
87 	size_t len = 0;
88 
89 	while (len < buflen) {
90 		if ((unsigned char)*in < 0x80) {		// ASCII range
91 			*out++ = *in;
92 			if (*in++ == '\0')			// End of string
93 				break;
94 			len++;
95 		} else if (((unsigned char)*in & 0xc0) == 0xc0) {  // Two-byte
96 			*out++ = ((in[0] & 0x1f) << 6) | (in[1] & 0x3f);
97 			in += 2;
98 			len++;
99 		} else if (((unsigned char)*in & 0xe0) == 0xe0) {  // Three-byte
100 			unsigned short three =	((in[0] & 0x0f) << 12) |
101 						 ((in[1] & 0x3f) << 6) |
102 						 (in[2] & 0x3f);
103 			*out++ = (three & 0xff00) >> 8;
104 			len++;
105 			if (len < buflen) {
106 				*out++ = (three & 0xff);
107 				len++;
108 			}
109 			in += 3;
110 		} else {
111 			in++;		// Unknown. Skip input.
112 		}
113 	}
114 	out[len-1] = '\0';
115 	return len;
116 }
117 int
getPasswordFromUser(wxString & result,const wxString & message,const wxString & caption,const wxString & defaultValue,wxWindow * parent)118 getPasswordFromUser(wxString& result, const wxString& message, const wxString& caption, const wxString& defaultValue, wxWindow *parent) {
119 	long style = wxTextEntryDialogStyle;
120 
121 	wxPasswordEntryDialog dialog(parent, message, caption, defaultValue, style);
122 
123 	int ret = dialog.ShowModal();
124 	if (ret == wxID_OK)
125 		result = dialog.GetValue();
126 
127 	return ret;
128 }
129 
130 static const char *error_strings[] = {
131 	__("Memory allocation failure"),			/* TQSL_ALLOC_ERROR */
132 	__("Unable to initialize random number generator"),	/* TQSL_RANDOM_ERROR */
133 	__("Invalid argument"),					/* TQSL_ARGUMENT_ERROR */
134 	__("Operator aborted operation"),			/* TQSL_OPERATOR_ABORT */
135 	__("No Certificate Request matches the selected Callsign Certificate"),/* TQSL_NOKEY_ERROR */
136 	__("Buffer too small"),					/* TQSL_BUFFER_ERROR */
137 	__("Invalid date format"),				/* TQSL_INVALID_DATE */
138 	__("Certificate not initialized for signing"),		/* TQSL_SIGNINIT_ERROR */
139 	__("Password not correct"),				/* TQSL_PASSWORD_ERROR */
140 	__("Expected name"),					/* TQSL_EXPECTED_NAME */
141 	__("Name exists"),					/* TQSL_NAME_EXISTS */
142 	__("Data for this DXCC entity could not be found"),	/* TQSL_NAME_NOT_FOUND */
143 	__("Invalid time format"),				/* TQSL_INVALID_TIME */
144 	__("QSO date is not within the date range specified on your Callsign Certificate"),	/* TQSL_CERT_DATE_MISMATCH */
145 	__("Certificate provider not found"),			/* TQSL_PROVIDER_NOT_FOUND */
146 	__("No callsign certificate for key"),			/* TQSL_CERT_KEY_ONLY */
147 	__("Configuration file cannot be opened"),		/* TQSL_CONFIG_ERROR */
148 	__("Callsign Certificate or Certificate Request not found"),/* TQSL_CERT_NOT_FOUND */
149 	__("PKCS#12 file not TQSL compatible"),			/* TQSL_PKCS12_ERROR */
150 	__("Callsign Certificate not TQSL compatible"),		/* TQSL_CERT_TYPE_ERROR */
151 	__("Date out of range"),				/* TQSL_DATE_OUT_OF_RANGE */
152 	__("Duplicate QSO suppressed"),				/* TQSL_DUPLICATE_QSO */
153 	__("Database error"),					/* TQSL_DB_ERROR */
154 	__("The selected station location could not be found"),	/* TQSL_LOCATION_NOT_FOUND */
155 	__("The selected callsign could not be found"),		/* TQSL_CALL_NOT_FOUND */
156 	__("The TQSL configuration file cannot be parsed"),	/* TQSL_CONFIG_SYNTAX_ERROR */
157 	__("This file can not be processed due to a system error"),	/* TQSL_FILE_SYSTEM_ERROR */
158 	__("The format of this file is incorrect."),		/* TQSL_FILE_SYNTAX_ERROR */
159 	__("Callsign certificate could not be installed"),	/* TQSL_CERT_ERROR */
160 };
161 
162 static wxString
getLocalizedErrorString_v(int err)163 getLocalizedErrorString_v(int err) {
164 	int adjusted_err;
165 	wxString buf;
166 
167 	if (err == 0)
168 		return _("NO ERROR");
169 	if (err == TQSL_CUSTOM_ERROR) {
170 		if (tQSL_CustomError[0] == 0) {
171 			return _("Unknown custom error");
172 		} else {
173 			return wxString::FromUTF8(tQSL_CustomError);
174 		}
175 	}
176 	if (err == TQSL_DB_ERROR && tQSL_CustomError[0] != 0) {
177 		return wxString::Format(_("Database Error: %hs"), tQSL_CustomError);
178 	}
179 
180 	if (err == TQSL_SYSTEM_ERROR || err == TQSL_FILE_SYSTEM_ERROR) {
181 		if (strlen(tQSL_ErrorFile) > 0) {
182 			buf = wxString::Format(_("System error: %hs : %hs"),
183 				tQSL_ErrorFile, strerror(tQSL_Errno));
184 			tQSL_ErrorFile[0] = '\0';
185 		} else {
186 			buf = wxString::Format(_("System error: %hs"),
187 				strerror(tQSL_Errno));
188 		}
189 		return buf;
190 	}
191 	if (err == TQSL_FILE_SYNTAX_ERROR) {
192 		if (strlen(tQSL_ErrorFile) > 0) {
193 			buf = wxString::Format(_("File syntax error: %hs"),
194 				tQSL_ErrorFile);
195 			tQSL_ErrorFile[0] = '\0';
196 		} else {
197 			buf = _("File syntax error");
198 		}
199 		return buf;
200 	}
201 	if (err == TQSL_OPENSSL_ERROR) {
202 		// Get error details from tqsllib as we have
203 		// no visibility into the tqsllib openssl context
204 		const char *msg = tqsl_getErrorString();
205 		return wxString::FromUTF8(msg);
206 	}
207 	if (err == TQSL_ADIF_ERROR) {
208 		if (strlen(tQSL_ErrorFile) > 0) {
209 			buf = wxString::Format(wxT("%hs: %hs"), tQSL_ErrorFile, tqsl_adifGetError(tQSL_ADIF_Error));
210 			tQSL_ErrorFile[0] = '\0';
211 		} else {
212 			buf = wxString::FromUTF8(tqsl_adifGetError(tQSL_ADIF_Error));
213 		}
214 		return buf;
215 	}
216 	if (err == TQSL_CABRILLO_ERROR) {
217 		if (strlen(tQSL_ErrorFile) > 0) {
218 			buf = wxString::Format(wxT("%hs: %hs"),
219 				tQSL_ErrorFile, tqsl_cabrilloGetError(tQSL_Cabrillo_Error));
220 			tQSL_ErrorFile[0] = '\0';
221 		} else {
222 			buf = wxString::FromUTF8(tqsl_cabrilloGetError(tQSL_Cabrillo_Error));
223 		}
224 		return buf;
225 	}
226 	if (err == TQSL_OPENSSL_VERSION_ERROR) {
227 		// No visibility into the tqsllib openssl context
228 		const char *msg = tqsl_getErrorString();
229 		return wxString::FromUTF8(msg);
230 	}
231 	if (err == TQSL_CERT_NOT_FOUND && tQSL_ImportCall[0] != '\0') {
232 		return wxString::Format(_("Callsign Certificate or Certificate Request not found for callsign %hs serial %ld"),
233 			tQSL_ImportCall, tQSL_ImportSerial);
234 	}
235 	adjusted_err = err - TQSL_ERROR_ENUM_BASE;
236 	if (adjusted_err < 0 ||
237 	    adjusted_err >=
238 		static_cast<int>(sizeof error_strings / sizeof error_strings[0])) {
239 		return wxString::Format(_("Invalid error code: %d"), err);
240 	}
241 	return wxGetTranslation(wxString::FromUTF8(error_strings[adjusted_err]));
242 }
243 
244 wxString
getLocalizedErrorString()245 getLocalizedErrorString() {
246 	wxString cp = getLocalizedErrorString_v(tQSL_Error);
247 	tQSL_Error = TQSL_NO_ERROR;
248 	tQSL_Errno = 0;
249 	tQSL_ErrorFile[0] = 0;
250 	tQSL_CustomError[0] = 0;
251 	return cp;
252 }
253