evolution-3.6.4/widgets/misc/e-port-entry.c

No issues found

  1 /*
  2  * This library is distributed in the hope that it will be useful,
  3  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  4  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  5  * Lesser General Public License for more details.
  6  *
  7  * You should have received a copy of the GNU Library General Public
  8  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  9  *
 10  * Authors:
 11  *	Dan Vratil <dvratil@redhat.com>
 12  */
 13 
 14 #include "e-port-entry.h"
 15 
 16 #include <config.h>
 17 #include <errno.h>
 18 #include <stddef.h>
 19 #include <string.h>
 20 
 21 #define E_PORT_ENTRY_GET_PRIVATE(obj) \
 22 	(G_TYPE_INSTANCE_GET_PRIVATE \
 23 	((obj), E_TYPE_PORT_ENTRY, EPortEntryPrivate))
 24 
 25 struct _EPortEntryPrivate {
 26 	CamelNetworkSecurityMethod method;
 27 	CamelProviderPortEntry *entries;
 28 };
 29 
 30 enum {
 31 	PORT_NUM_COLUMN,
 32 	PORT_DESC_COLUMN,
 33 	PORT_IS_SSL_COLUMN
 34 };
 35 
 36 enum {
 37 	PROP_0,
 38 	PROP_IS_VALID,
 39 	PROP_PORT,
 40 	PROP_SECURITY_METHOD
 41 };
 42 
 43 G_DEFINE_TYPE (
 44 	EPortEntry,
 45 	e_port_entry,
 46 	GTK_TYPE_COMBO_BOX)
 47 
 48 static GtkEntry *
 49 port_entry_get_entry (EPortEntry *port_entry)
 50 {
 51 	return GTK_ENTRY (gtk_bin_get_child (GTK_BIN (port_entry)));
 52 }
 53 
 54 static gboolean
 55 port_entry_get_numeric_port (EPortEntry *port_entry,
 56                              gint *out_port)
 57 {
 58 	GtkEntry *entry;
 59 	const gchar *port_string;
 60 	gboolean valid;
 61 	gint port;
 62 
 63 	entry = port_entry_get_entry (port_entry);
 64 
 65 	port_string = gtk_entry_get_text (entry);
 66 	g_return_val_if_fail (port_string != NULL, FALSE);
 67 
 68 	errno = 0;
 69 	port = strtol (port_string, NULL, 10);
 70 	valid = (errno == 0) && (port == CLAMP (port, 1, G_MAXUINT16));
 71 
 72 	if (valid && out_port != NULL)
 73 		*out_port = port;
 74 
 75 	return valid;
 76 }
 77 
 78 static void
 79 port_entry_text_changed (GtkEditable *editable,
 80                          EPortEntry *port_entry)
 81 {
 82 	GObject *object = G_OBJECT (port_entry);
 83 	const gchar *desc = NULL;
 84 	gint port = 0;
 85 	gint ii = 0;
 86 
 87 	g_object_freeze_notify (object);
 88 
 89 	port_entry_get_numeric_port (port_entry, &port);
 90 
 91 	if (port_entry->priv->entries != NULL) {
 92 		while (port_entry->priv->entries[ii].port > 0) {
 93 			if (port == port_entry->priv->entries[ii].port) {
 94 				desc = port_entry->priv->entries[ii].desc;
 95 				break;
 96 			}
 97 			ii++;
 98 		}
 99 	}
100 
101 	if (desc != NULL)
102 		gtk_widget_set_tooltip_text (GTK_WIDGET (port_entry), desc);
103 	else
104 		gtk_widget_set_has_tooltip (GTK_WIDGET (port_entry), FALSE);
105 
106 	g_object_notify (object, "port");
107 	g_object_notify (object, "is-valid");
108 
109 	g_object_thaw_notify (object);
110 }
111 
112 static void
113 port_entry_method_changed (EPortEntry *port_entry)
114 {
115 	CamelNetworkSecurityMethod method;
116 	gboolean standard_port = FALSE;
117 	gboolean valid, have_ssl = FALSE, have_nossl = FALSE;
118 	gint port = 0;
119 	gint ii;
120 
121 	method = e_port_entry_get_security_method (port_entry);
122 	valid = port_entry_get_numeric_port (port_entry, &port);
123 
124 	/* Only change the port number if it's currently on a standard
125 	 * port (i.e. listed in a CamelProviderPortEntry).  Otherwise,
126 	 * leave custom port numbers alone. */
127 
128 	if (valid && port_entry->priv->entries != NULL) {
129 		for (ii = 0; port_entry->priv->entries[ii].port > 0 && (!have_ssl || !have_nossl); ii++) {
130 			/* Use only the first SSL/no-SSL port as a default in the list
131 			 * and skip the others */
132 			if (port_entry->priv->entries[ii].is_ssl) {
133 				if (have_ssl)
134 					continue;
135 				have_ssl = TRUE;
136 			} else {
137 				if (have_nossl)
138 					continue;
139 				have_nossl = TRUE;
140 			}
141 
142 			if (port == port_entry->priv->entries[ii].port) {
143 				standard_port = TRUE;
144 				break;
145 			}
146 		}
147 	}
148 
149 	if (valid && !standard_port)
150 		return;
151 
152 	switch (method) {
153 		case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
154 			e_port_entry_activate_secured_port (port_entry, 0);
155 			break;
156 		default:
157 			e_port_entry_activate_nonsecured_port (port_entry, 0);
158 			break;
159 	}
160 }
161 
162 static void
163 port_entry_set_property (GObject *object,
164                          guint property_id,
165                          const GValue *value,
166                          GParamSpec *pspec)
167 {
168 	switch (property_id) {
169 		case PROP_PORT:
170 			e_port_entry_set_port (
171 				E_PORT_ENTRY (object),
172 				g_value_get_uint (value));
173 			return;
174 
175 		case PROP_SECURITY_METHOD:
176 			e_port_entry_set_security_method (
177 				E_PORT_ENTRY (object),
178 				g_value_get_enum (value));
179 			return;
180 	}
181 
182 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
183 }
184 
185 static void
186 port_entry_get_property (GObject *object,
187                          guint property_id,
188                          GValue *value,
189                          GParamSpec *pspec)
190 {
191 	switch (property_id) {
192 		case PROP_IS_VALID:
193 			g_value_set_boolean (
194 				value, e_port_entry_is_valid (
195 				E_PORT_ENTRY (object)));
196 			return;
197 
198 		case PROP_PORT:
199 			g_value_set_uint (
200 				value, e_port_entry_get_port (
201 				E_PORT_ENTRY (object)));
202 			return;
203 
204 		case PROP_SECURITY_METHOD:
205 			g_value_set_enum (
206 				value, e_port_entry_get_security_method (
207 				E_PORT_ENTRY (object)));
208 			return;
209 	}
210 
211 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
212 }
213 
214 static void
215 port_entry_constructed (GObject *object)
216 {
217 	GtkEntry *entry;
218 
219 	/* Chain up to parent's constructed() method. */
220 	G_OBJECT_CLASS (e_port_entry_parent_class)->constructed (object);
221 
222 	entry = port_entry_get_entry (E_PORT_ENTRY (object));
223 
224 	g_signal_connect_after (
225 		entry, "changed",
226 		G_CALLBACK (port_entry_text_changed), object);
227 }
228 
229 static void
230 port_entry_get_preferred_width (GtkWidget *widget,
231                                 gint *minimum_size,
232                                 gint *natural_size)
233 {
234 	PangoContext *context;
235 	PangoFontMetrics *metrics;
236 	PangoFontDescription *font_desc;
237 	GtkStyleContext *style_context;
238 	GtkStateFlags state;
239 	gint digit_width;
240 	gint parent_entry_width_min;
241 	gint parent_width_min;
242 	GtkWidget *entry;
243 
244 	style_context = gtk_widget_get_style_context (widget);
245 	state = gtk_widget_get_state_flags (widget);
246 	gtk_style_context_get (
247 		style_context, state, "font", &font_desc, NULL);
248 	context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
249 	metrics = pango_context_get_metrics (
250 		context, font_desc, pango_context_get_language (context));
251 
252 	digit_width = PANGO_PIXELS (
253 		pango_font_metrics_get_approximate_digit_width (metrics));
254 
255 	/* Preferred width of the entry */
256 	entry = gtk_bin_get_child (GTK_BIN (widget));
257 	gtk_widget_get_preferred_width (entry, NULL, &parent_entry_width_min);
258 
259 	/* Preferred width of a standard combobox */
260 	GTK_WIDGET_CLASS (e_port_entry_parent_class)->
261 		get_preferred_width (widget, &parent_width_min, NULL);
262 
263 	/* 6 * digit_width - port number has max 5
264 	 * digits + extra free space for better look */
265 	if (minimum_size != NULL)
266 		*minimum_size =
267 			parent_width_min - parent_entry_width_min +
268 			6 * digit_width;
269 
270 	if (natural_size != NULL)
271 		*natural_size =
272 			parent_width_min - parent_entry_width_min +
273 			6 * digit_width;
274 
275 	pango_font_metrics_unref (metrics);
276 	pango_font_description_free (font_desc);
277 }
278 
279 static void
280 e_port_entry_class_init (EPortEntryClass *class)
281 {
282 	GObjectClass *object_class;
283 	GtkWidgetClass *widget_class;
284 
285 	g_type_class_add_private (class, sizeof (EPortEntryPrivate));
286 
287 	object_class = G_OBJECT_CLASS (class);
288 	object_class->set_property = port_entry_set_property;
289 	object_class->get_property = port_entry_get_property;
290 	object_class->constructed = port_entry_constructed;
291 
292 	widget_class = GTK_WIDGET_CLASS (class);
293 	widget_class->get_preferred_width = port_entry_get_preferred_width;
294 
295 	g_object_class_install_property (
296 		object_class,
297 		PROP_IS_VALID,
298 		g_param_spec_boolean (
299 			"is-valid",
300 			NULL,
301 			NULL,
302 			FALSE,
303 			G_PARAM_READABLE |
304 			G_PARAM_STATIC_STRINGS));
305 
306 	g_object_class_install_property (
307 		object_class,
308 		PROP_PORT,
309 		g_param_spec_uint (
310 			"port",
311 			NULL,
312 			NULL,
313 			0,		/* Min port, 0 = invalid port */
314 			G_MAXUINT16,	/* Max port */
315 			0,
316 			G_PARAM_READWRITE |
317 			G_PARAM_STATIC_STRINGS));
318 
319 	g_object_class_install_property (
320 		object_class,
321 		PROP_SECURITY_METHOD,
322 		g_param_spec_enum (
323 			"security-method",
324 			"Security Method",
325 			"Method used to establish a network connection",
326 			CAMEL_TYPE_NETWORK_SECURITY_METHOD,
327 			CAMEL_NETWORK_SECURITY_METHOD_NONE,
328 			G_PARAM_READWRITE |
329 			G_PARAM_STATIC_STRINGS));
330 }
331 
332 static void
333 e_port_entry_init (EPortEntry *port_entry)
334 {
335 	GtkCellRenderer *renderer;
336 	GtkListStore *store;
337 
338 	port_entry->priv = E_PORT_ENTRY_GET_PRIVATE (port_entry);
339 
340 	store = gtk_list_store_new (
341 		3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
342 
343 	gtk_combo_box_set_model (
344 		GTK_COMBO_BOX (port_entry), GTK_TREE_MODEL (store));
345 	gtk_combo_box_set_entry_text_column (
346 		GTK_COMBO_BOX (port_entry), PORT_NUM_COLUMN);
347 	gtk_combo_box_set_id_column (
348 		GTK_COMBO_BOX (port_entry), PORT_NUM_COLUMN);
349 
350 	renderer = gtk_cell_renderer_text_new ();
351 	gtk_cell_renderer_set_sensitive (renderer, TRUE);
352 	gtk_cell_layout_pack_start (
353 		GTK_CELL_LAYOUT (port_entry), renderer, FALSE);
354 	gtk_cell_layout_add_attribute (
355 		GTK_CELL_LAYOUT (port_entry),
356 		renderer, "text", PORT_NUM_COLUMN);
357 
358 	renderer = gtk_cell_renderer_text_new ();
359 	gtk_cell_renderer_set_sensitive (renderer, FALSE);
360 	gtk_cell_layout_pack_start (
361 		GTK_CELL_LAYOUT (port_entry), renderer, TRUE);
362 	gtk_cell_layout_add_attribute (
363 		GTK_CELL_LAYOUT (port_entry),
364 		renderer, "text", PORT_DESC_COLUMN);
365 }
366 
367 GtkWidget *
368 e_port_entry_new (void)
369 {
370 	return g_object_new (
371 		E_TYPE_PORT_ENTRY, "has-entry", TRUE, NULL);
372 }
373 
374 void
375 e_port_entry_set_camel_entries (EPortEntry *port_entry,
376                                 CamelProviderPortEntry *entries)
377 {
378 	GtkComboBox *combo_box;
379 	GtkTreeIter iter;
380 	GtkTreeModel *model;
381 	GtkListStore *store;
382 	gint port = 0;
383 	gint i = 0;
384 
385 	g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
386 	g_return_if_fail (entries);
387 
388 	port_entry->priv->entries = entries;
389 
390 	combo_box = GTK_COMBO_BOX (port_entry);
391 	model = gtk_combo_box_get_model (combo_box);
392 
393 	store = GTK_LIST_STORE (model);
394 	gtk_list_store_clear (store);
395 
396 	while (entries[i].port > 0) {
397 		gchar *port_string;
398 
399 		/* Grab the first port number. */
400 		if (port == 0)
401 			port = entries[i].port;
402 
403 		port_string = g_strdup_printf ("%i", entries[i].port);
404 
405 		gtk_list_store_append (store, &iter);
406 		gtk_list_store_set (
407 			store, &iter,
408 			PORT_NUM_COLUMN, port_string,
409 			PORT_DESC_COLUMN, entries[i].desc,
410 			PORT_IS_SSL_COLUMN, entries[i].is_ssl,
411 			-1);
412 		i++;
413 
414 		g_free (port_string);
415 	}
416 
417 	e_port_entry_set_port (port_entry, port);
418 }
419 
420 gint
421 e_port_entry_get_port (EPortEntry *port_entry)
422 {
423 	gint port = 0;
424 
425 	g_return_val_if_fail (E_IS_PORT_ENTRY (port_entry), 0);
426 
427 	port_entry_get_numeric_port (port_entry, &port);
428 
429 	return port;
430 }
431 
432 void
433 e_port_entry_set_port (EPortEntry *port_entry,
434                        gint port)
435 {
436 	GtkEntry *entry;
437 	gchar *port_string;
438 
439 	g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
440 
441 	entry = port_entry_get_entry (port_entry);
442 	port_string = g_strdup_printf ("%i", port);
443 	gtk_entry_set_text (entry, port_string);
444 	g_free (port_string);
445 }
446 
447 gboolean
448 e_port_entry_is_valid (EPortEntry *port_entry)
449 {
450 	g_return_val_if_fail (E_IS_PORT_ENTRY (port_entry), FALSE);
451 
452 	return port_entry_get_numeric_port (port_entry, NULL);
453 }
454 
455 CamelNetworkSecurityMethod
456 e_port_entry_get_security_method (EPortEntry *port_entry)
457 {
458 	g_return_val_if_fail (
459 		E_IS_PORT_ENTRY (port_entry),
460 		CAMEL_NETWORK_SECURITY_METHOD_NONE);
461 
462 	return port_entry->priv->method;
463 }
464 
465 void
466 e_port_entry_set_security_method (EPortEntry *port_entry,
467                                   CamelNetworkSecurityMethod method)
468 {
469 	g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
470 
471 	port_entry->priv->method = method;
472 
473 	port_entry_method_changed (port_entry);
474 
475 	g_object_notify (G_OBJECT (port_entry), "security-method");
476 }
477 
478 /**
479  * If there are more then one secured port in the model, you can specify
480  * which of the secured ports should be activated by specifying the index.
481  * The index counts only for secured ports, so if you have 5 ports of which
482  * ports 1, 3 and 5 are secured, the association is 0=>1, 1=>3, 2=>5
483  */
484 void
485 e_port_entry_activate_secured_port (EPortEntry *port_entry,
486                                     gint index)
487 {
488 	GtkTreeModel *model;
489 	GtkTreeIter iter;
490 	gboolean is_ssl;
491 	gint iters = 0;
492 
493 	g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
494 
495 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (port_entry));
496 
497 	if (!gtk_tree_model_get_iter_first (model, &iter))
498 		return;
499 
500 	do {
501 		gtk_tree_model_get (
502 			model, &iter, PORT_IS_SSL_COLUMN, &is_ssl, -1);
503 		if (is_ssl && (iters == index)) {
504 			gtk_combo_box_set_active_iter (
505 				GTK_COMBO_BOX (port_entry), &iter);
506 			return;
507 		}
508 
509 		if (is_ssl)
510 			iters++;
511 
512 	} while (gtk_tree_model_iter_next (model, &iter));
513 }
514 
515 /**
516  * If there are more then one unsecured port in the model, you can specify
517  * which of the unsecured ports should be activated by specifiying the index.
518  * The index counts only for unsecured ports, so if you have 5 ports, of which
519  * ports 2 and 4 are unsecured, the associtation is 0=>2, 1=>4
520  */
521 void
522 e_port_entry_activate_nonsecured_port (EPortEntry *port_entry,
523                                        gint index)
524 {
525 	GtkTreeModel *model;
526 	GtkTreeIter iter;
527 	gboolean is_ssl;
528 	gint iters = 0;
529 
530 	g_return_if_fail (E_IS_PORT_ENTRY (port_entry));
531 
532 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (port_entry));
533 
534 	if (!gtk_tree_model_get_iter_first (model, &iter))
535 		return;
536 
537 	do {
538 		gtk_tree_model_get (model, &iter, PORT_IS_SSL_COLUMN, &is_ssl, -1);
539 		if (!is_ssl && (iters == index)) {
540 			gtk_combo_box_set_active_iter (
541 				GTK_COMBO_BOX (port_entry), &iter);
542 			return;
543 		}
544 
545 		if (!is_ssl)
546 			iters++;
547 
548 	} while (gtk_tree_model_iter_next (model, &iter));
549 }