1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #define _BSD_SOURCE
21 
22 #include <unistd.h>
23 #include <string.h>
24 
25 #include "applet-struct.h"
26 #include "applet-connections.h"
27 #include "applet-menu.h"
28 
cd_NetworkMonitor_get_connections_for_access_point(const gchar * cAccessPoint,const gchar * cDevice,const gchar * cSsid,const gchar * cHwAddress,int iMode,int iWirelessCapabilities,GPtrArray * paConnections,GPtrArray * paSettings)29 static GList *cd_NetworkMonitor_get_connections_for_access_point (const gchar *cAccessPoint, const gchar *cDevice, const gchar *cSsid, const gchar *cHwAddress, int iMode, int iWirelessCapabilities, GPtrArray *paConnections, GPtrArray *paSettings)
30 {
31 	g_return_val_if_fail (paConnections != NULL, NULL);
32 	GList *pConnList = NULL;
33 	gchar *cConnection;
34 	GHashTable *pSettings, *pSubSettings;
35 	GValue *v;
36 	uint i;
37 	for (i = 0; i < paConnections->len; i++)
38 	{
39 		cConnection = (gchar *)g_ptr_array_index(paConnections, i);
40 		cd_debug (" Connection path : %s", cConnection);
41 
42 		pSettings = g_ptr_array_index (paSettings, i);
43 
44 		pSubSettings = g_hash_table_lookup (pSettings, "connection");
45 		if (pSubSettings == NULL)
46 			continue;
47 
48 		const gchar *cType = NULL;
49 		v = g_hash_table_lookup (pSubSettings, "type");
50 		if (v && G_VALUE_HOLDS_STRING (v))
51 		{
52 			cType = g_value_get_string (v);
53 			cd_debug (" type : %s", cType);
54 		}
55 		if (cType == NULL || strcmp (cType, "802-11-wireless") != 0)  // on veut du wifi.
56 			continue;
57 
58 		const gchar *cID = NULL;
59 		v = g_hash_table_lookup (pSubSettings, "id");
60 		if (v && G_VALUE_HOLDS_STRING (v))
61 		{
62 			cID = g_value_get_string (v);
63 			cd_debug (" id : %s", cID);
64 		}
65 
66 		pSubSettings = g_hash_table_lookup (pSettings, "802-11-wireless");
67 		if (pSubSettings == NULL)
68 			continue;
69 		const gchar *cMode = NULL;
70 		v = g_hash_table_lookup (pSubSettings, "mode");
71 		if (v && G_VALUE_HOLDS_STRING (v))
72 		{
73 			cMode = g_value_get_string (v);
74 			cd_debug (" mode : %s", cMode);
75 		}
76 		if (iMode && cMode)
77 		{
78 			if (iMode == 1 && strcmp (cMode, "ad-hoc") != 0)
79 				continue;
80 			if (iMode == 2 && strcmp (cMode, "infrastructure") != 0)
81 				continue;
82 		}
83 
84 		gchar *cAPSsid = NULL;
85 		v = g_hash_table_lookup (pSubSettings, "ssid");
86 		if (v && G_VALUE_HOLDS_BOXED (v))
87 		{
88 			GByteArray *a = g_value_get_boxed (v);
89 			cAPSsid = g_strndup ((gchar *) a->data, a->len);
90 			cd_debug (" ssid : %s", cSsid);
91 		}
92 		if (cSsid == NULL || (cAPSsid != NULL && strcmp (cAPSsid, cSsid) != 0))  // le SSID est necessaire.
93 			continue;
94 
95 		const gchar *cMacAddress = NULL;
96 		v = g_hash_table_lookup (pSubSettings, "mac-address");
97 		if (v && G_VALUE_HOLDS_STRING (v))
98 		{
99 			cMacAddress = g_value_get_string (v);
100 			cd_debug (" mac address : %s", cMacAddress);
101 		}
102 		if (cHwAddress != NULL && cMacAddress != NULL && strcmp (cMacAddress, cHwAddress) != 0)
103 			continue;
104 
105 		pSubSettings = g_hash_table_lookup (pSettings, "802-11-wireless-security");
106 		if (pSubSettings)
107 		{
108 			/// on verra plus tard ...
109 
110 		}
111 
112 		pConnList = g_list_prepend (pConnList, GINT_TO_POINTER (i));
113 	}
114 
115 	return pConnList;
116 }
117 
118 /* Not used
119 static GList *cd_NetworkMonitor_get_connections_for_wired_device (const gchar *cDevice, const gchar *cHwAddress, GPtrArray *paConnections)
120 {
121 	GList *pConnList = NULL;
122 	//\_____________ On cherche une connection qui ait le meme type (wifi ou filaire), et soit le meme SSID, soit la meme interface.
123 	gchar *cConnection;
124 	uint i;
125 	for (i = 0; i < paConnections->len; i++)
126 	{
127 		cConnection = (gchar *)g_ptr_array_index(paConnections, i);
128 		cd_debug (" Connection path : %s", cConnection);
129 
130 	}
131 
132 	return pConnList;
133 }
134 */
135 
_on_select_access_point(GtkMenuItem * menu_item,CDMenuItemData * pItemData)136 static void _on_select_access_point (GtkMenuItem *menu_item, CDMenuItemData *pItemData)
137 {
138 	if (pItemData == NULL || pItemData->cConnection == NULL)
139 	{
140 		/// il faut creer une connection ...
141 		cd_debug ("aucune des connexions existantes ne convient pour ce point d'acces\n");
142 
143 		GHashTable *pSettings = g_hash_table_new_full (g_str_hash,
144 			g_str_equal,
145 			g_free,
146 			(GDestroyNotify) g_hash_table_destroy);  // a table of tables.
147 		GHashTable *pSubSettings;
148 
149 		// connection: type, id, uuid
150 		pSubSettings = g_hash_table_new_full (g_str_hash,
151 			g_str_equal,
152 			g_free,
153 			g_free);
154 		g_hash_table_insert (pSettings, g_strdup ("connection"), pSubSettings);
155 		g_hash_table_insert (pSubSettings, g_strdup ("type"), g_strdup ("802-11-wireless"));
156 		g_hash_table_insert (pSubSettings, g_strdup ("id"), g_strdup_printf ("CD - %s", pItemData->cSsid));
157 
158 		// 802-11-wireless: ssid, mode, seen-bssids
159 		pSubSettings = g_hash_table_new_full (g_str_hash,
160 			g_str_equal,
161 			g_free,
162 			g_free);
163 		g_hash_table_insert (pSettings, g_strdup ("802-11-wireless"), pSubSettings);
164 		g_hash_table_insert (pSubSettings, g_strdup ("ssid"), g_strdup (pItemData->cSsid));
165 		g_hash_table_insert (pSubSettings, g_strdup ("mode"), g_strdup ("infrastructure"));
166 
167 		// AddConnection
168 		DBusGProxy *dbus_proxy_Settings = cairo_dock_create_new_system_proxy (
169 			myData.cServiceName,
170 			"/org/freedesktop/NetworkManagerSettings",
171 			"org.freedesktop.NetworkManagerSettings");
172 
173 		GError *erreur = NULL;
174 		dbus_g_proxy_call (dbus_proxy_Settings, "AddConnection", &erreur,
175 			CD_DBUS_TYPE_HASH_TABLE_OF_HASH_TABLE, pSettings,
176 			G_TYPE_INVALID,
177 			G_TYPE_INVALID);
178 		if (erreur != NULL)
179 		{
180 			cd_warning (erreur->message);
181 			g_error_free (erreur);
182 			return ;
183 		}
184 
185 		/// on attend le signal NewConnection ...
186 
187 
188 
189 		/// on active la connexion...
190 
191 
192 
193 	}
194 	else
195 	{
196 		cd_debug ("on a choisit (%s; %s; %s)", pItemData->cAccessPoint, pItemData->cDevice, pItemData->cConnection);
197 
198 		//ActivateConnection ( s: service_name, o: connection, o: device, o: specific_object )o
199 		GError *erreur = NULL;
200 		GValue active_connection_path = G_VALUE_INIT;
201 		g_value_init (&active_connection_path, DBUS_TYPE_G_OBJECT_PATH);
202 
203 		gchar *cNewActiveConnectionPath = NULL;
204 		dbus_g_proxy_call (myData.dbus_proxy_NM, "ActivateConnection", &erreur,
205 			G_TYPE_STRING, myData.cServiceName,
206 			DBUS_TYPE_G_OBJECT_PATH, pItemData->cConnection,
207 			DBUS_TYPE_G_OBJECT_PATH, pItemData->cDevice,
208 			DBUS_TYPE_G_OBJECT_PATH, pItemData->cAccessPoint,
209 			G_TYPE_INVALID,
210 			DBUS_TYPE_G_OBJECT_PATH, &cNewActiveConnectionPath,
211 			G_TYPE_INVALID);
212 		if (erreur != NULL)
213 		{
214 			cd_warning (erreur->message);
215 			g_error_free (erreur);
216 			return ;
217 		}
218 		cd_debug (" => new active connection path : %s", cNewActiveConnectionPath);
219 	}
220 }
221 
cd_NetworkMonitor_build_menu_with_access_points(void)222 GtkWidget * cd_NetworkMonitor_build_menu_with_access_points (void)
223 {
224 	//\_____________ On recupere les connections existantes, ainsi que leur settings.
225 	DBusGProxy *dbus_proxy_Settings = cairo_dock_create_new_system_proxy (
226 		myData.cServiceName,
227 		"/org/freedesktop/NetworkManagerSettings",
228 		"org.freedesktop.NetworkManagerSettings");
229 	GPtrArray *paConnections = cairo_dock_dbus_get_array (dbus_proxy_Settings, "ListConnections");
230 	cd_debug ("%d connection(s)", paConnections ? paConnections->len : 0);
231 	g_object_unref (dbus_proxy_Settings);
232 
233 	GPtrArray *paSettings = NULL;
234 	gchar *cConnection;
235 	if (paConnections != NULL && paConnections->len > 0)
236 	{
237 		paSettings = g_ptr_array_sized_new (paConnections->len);
238 		g_ptr_array_set_size (paSettings, paConnections->len);
239 		DBusGProxy *dbus_proxy_ConnectionSettings;
240 		GError *erreur = NULL;
241 		GHashTable *pSettingsTable;
242 		uint i;
243 		for (i = 0; i < paConnections->len; i++)
244 		{
245 			cConnection = (gchar *)g_ptr_array_index(paConnections, i);
246 			cd_debug (" Connection path : %s", cConnection);
247 
248 			dbus_proxy_ConnectionSettings = cairo_dock_create_new_system_proxy (
249 				"org.freedesktop.NetworkManagerUserSettings",
250 				cConnection,
251 				"org.freedesktop.NetworkManagerSettings.Connection");
252 			erreur = NULL;
253 			pSettingsTable = NULL;
254 			dbus_g_proxy_call (dbus_proxy_ConnectionSettings, "GetSettings", &erreur,
255 				G_TYPE_INVALID,
256 				CD_DBUS_TYPE_HASH_TABLE_OF_HASH_TABLE, &pSettingsTable,
257 				G_TYPE_INVALID);
258 			if (erreur != NULL)
259 			{
260 				cd_warning (erreur->message);
261 				g_error_free (erreur);
262 				erreur = NULL;
263 			}
264 			paSettings->pdata[i] = pSettingsTable;
265 
266 			g_object_unref (dbus_proxy_ConnectionSettings);
267 		}
268 	}
269 
270 	//\_____________ On recupere la liste des devices.
271 	GPtrArray *paDevices = cairo_dock_dbus_get_array (myData.dbus_proxy_NM, "GetDevices");
272 	g_return_val_if_fail (paDevices != NULL, FALSE);
273 	cd_debug ("%d device(s)", paDevices->len);
274 
275 	GtkWidget *pMenu = gldi_menu_new (myIcon);
276 
277 	//\_____________ On parcourt tous les devices.
278 	GHashTable *pSsidTable = g_hash_table_new_full (g_str_hash,
279 		g_str_equal,
280 		g_free,
281 		NULL);
282 	gchar *cDevice;
283 	DBusGProxy *dbus_proxy_Device_prop;
284 	guint iDeviceType;
285 	DBusGProxy *dbus_proxy_WirelessDevice;
286 	DBusGProxy *dbus_proxy_AccessPoint_prop;
287 	gchar *cAccessPointPath;
288 	GHashTable *hProperties;
289 	GValue *v;
290 	gint iPercent;
291 	gchar *cSsid = NULL;
292 	const gchar *cHwAddress;
293 	CDMenuItemData *pItemData;
294 	uint i, j;
295 	for (i = 0; i < paDevices->len; i++)
296 	{
297 		// on recupere le device.
298 		cDevice = (gchar *)g_ptr_array_index(paDevices, i);
299 		dbus_proxy_Device_prop = cairo_dock_create_new_system_proxy (
300 			"org.freedesktop.NetworkManager",
301 			cDevice,
302 			"org.freedesktop.DBus.Properties");
303 		if (!DBUS_IS_G_PROXY (dbus_proxy_Device_prop))
304 			continue;
305 		cd_debug (" device %s", cDevice);
306 
307 		// on regarde son type.
308 		iDeviceType = cairo_dock_dbus_get_property_as_uint (dbus_proxy_Device_prop, "org.freedesktop.NetworkManager.Device", "DeviceType");  // 1 : ethernet, 2 : wifi
309 		cd_debug (" device type : %d", iDeviceType);
310 		if (iDeviceType != 1 && iDeviceType != 2)  // ne nous insteresse pas.
311 		{
312 			cd_debug (" useless device type\n");
313 			g_object_unref (dbus_proxy_Device_prop);
314 			continue;
315 		}
316 
317 		if (iDeviceType == 2)
318 		{
319 			// On recupere ses proprietes.
320 			hProperties = cairo_dock_dbus_get_all_properties (dbus_proxy_Device_prop, "org.freedesktop.NetworkManager.Device.Wireless");
321 
322 			/*v = (GValue *)g_hash_table_lookup (hProperties, "HwAddress");
323 			if (v && G_VALUE_HOLDS_STRING (v))
324 			{
325 				cAccessPointHwAdress = g_value_get_string (v);
326 			}*/
327 
328 			int iMode = 0;
329 			v = (GValue *)g_hash_table_lookup (hProperties, "Mode");
330 			if (v && G_VALUE_HOLDS_UINT (v))
331 			{
332 				iMode = g_value_get_uint (v);
333 			}
334 
335 			int iWirelessCapabilities = 0;
336 			v = (GValue *)g_hash_table_lookup (hProperties, "WirelessCapabilities");
337 			if (v && G_VALUE_HOLDS_UINT (v))
338 			{
339 				iWirelessCapabilities = g_value_get_uint (v);
340 			}
341 
342 			// On recupere la liste des points d'acces.
343 			dbus_proxy_WirelessDevice = cairo_dock_create_new_system_proxy (
344 			"org.freedesktop.NetworkManager",
345 				cDevice,
346 				"org.freedesktop.NetworkManager.Device.Wireless");
347 			GError *erreur = NULL;
348 			GPtrArray *pAccessPoints = NULL;
349 			dbus_g_proxy_call (dbus_proxy_WirelessDevice, "GetAccessPoints", &erreur,
350 				G_TYPE_INVALID,
351 				dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &pAccessPoints,
352 				G_TYPE_INVALID);
353 			g_object_unref (dbus_proxy_WirelessDevice);
354 			if (erreur != NULL)
355 			{
356 				cd_warning (erreur->message);
357 				g_error_free (erreur);
358 				erreur = NULL;
359 				g_object_unref (dbus_proxy_Device_prop);
360 				continue;
361 			}
362 			if (!pAccessPoints || pAccessPoints->len == 0)
363 			{
364 				cd_debug ("  aucun point d'acces\n");
365 				g_object_unref (dbus_proxy_Device_prop);
366 				/// ajouter une entree pour dire si le wifi est desactive ...
367 
368 				continue;
369 			}
370 
371 			// on insere chaque point d'acces dans le menu.
372 			for (j = 0; j < pAccessPoints->len; j ++)
373 			{
374 				// on recupere le point d'acces.
375 				cAccessPointPath = (gchar *)g_ptr_array_index (pAccessPoints, j);
376 				dbus_proxy_AccessPoint_prop = cairo_dock_create_new_system_proxy (
377 				"org.freedesktop.NetworkManager",
378 					cAccessPointPath,
379 					"org.freedesktop.DBus.Properties");
380 
381 				// on recupere ses proprietes.
382 				hProperties = cairo_dock_dbus_get_all_properties (dbus_proxy_AccessPoint_prop, "org.freedesktop.NetworkManager.AccessPoint");
383 				if (hProperties == NULL)
384 				{
385 					g_object_unref (dbus_proxy_AccessPoint_prop);
386 					continue;
387 				}
388 
389 				iPercent = 0;
390 				v = (GValue *)g_hash_table_lookup (hProperties, "Strength");
391 				if (v != NULL && G_VALUE_HOLDS_UCHAR (v))
392 				{
393 					iPercent = g_value_get_uchar (v);
394 				}
395 
396 				v = (GValue *)g_hash_table_lookup (hProperties, "Ssid");
397 				if (v != NULL && G_VALUE_HOLDS_BOXED (v))
398 				{
399 					GByteArray *a = g_value_get_boxed (v);
400 					cSsid = g_strndup ((gchar *) a->data, a->len);
401 				}
402 
403 				// on empeche les doublons.
404 				pItemData = (cSsid ? g_hash_table_lookup (pSsidTable, cSsid) : NULL);
405 				if (pItemData != NULL)
406 				{
407 					if (pItemData->iPercent > iPercent)
408 					{
409 						g_free (cSsid);
410 						g_object_unref (dbus_proxy_AccessPoint_prop);
411 					}
412 					else
413 					{
414 						g_free (pItemData->cAccessPoint);
415 						pItemData->cAccessPoint = g_strdup (cAccessPointPath);
416 					}
417 					continue;
418 				}
419 
420 				cHwAddress = NULL;
421 				v = (GValue *)g_hash_table_lookup (hProperties, "HwAddress");
422 				if (v != NULL && G_VALUE_HOLDS_STRING (v))
423 				{
424 					cHwAddress = g_value_get_string (v);
425 				}
426 
427 				iMode = 0;
428 				v = (GValue *)g_hash_table_lookup (hProperties, "Mode");
429 				if (v != NULL && G_VALUE_HOLDS_UINT (v))
430 				{
431 					iMode = g_value_get_uint (v);
432 				}
433 
434 				iWirelessCapabilities = 0;
435 				v = (GValue *)g_hash_table_lookup (hProperties, "WpaFlags");
436 				if (v != NULL && G_VALUE_HOLDS_UINT (v))
437 				{
438 					iWirelessCapabilities = g_value_get_uint (v);
439 				}
440 
441 				cd_debug ("%d) %s : %s (%s, %d%%)", j, cSsid, cAccessPointPath, cHwAddress, iPercent);
442 
443 				const gchar *cImage = NULL;
444 				if (iPercent > 80)
445 					cImage = MY_APPLET_SHARE_DATA_DIR"/link-5.svg";
446 				else if (iPercent > 60)
447 					cImage = MY_APPLET_SHARE_DATA_DIR"/link-4.svg";
448 				else if (iPercent > 40)
449 					cImage = MY_APPLET_SHARE_DATA_DIR"/link-3.svg";
450 				else if (iPercent > 20)
451 					cImage = MY_APPLET_SHARE_DATA_DIR"/link-2.svg";
452 				else if (iPercent > 0)
453 					cImage = MY_APPLET_SHARE_DATA_DIR"/link-1.svg";
454 				else
455 					cImage = MY_APPLET_SHARE_DATA_DIR"/link-0.svg";
456 
457 				/// recuperer les flags, wpa flags, et rsn flags -> encrypted.
458 				/// et le mode -> ad_hoc
459 				/// et mettre une icone asociee dans une hbox...
460 
461 				// on cherche une connection qui convienne.
462 				GList *pConnList = cd_NetworkMonitor_get_connections_for_access_point (cAccessPointPath, cDevice, cSsid, cHwAddress, iMode, iWirelessCapabilities, paConnections, paSettings);
463 
464 				cd_debug ("%d connexion(s) satisfont a ce point d'acces", g_list_length (pConnList));
465 
466 				if (pConnList == NULL || pConnList->next == NULL)
467 				{
468 					if (pItemData == NULL)
469 					{
470 						pItemData = g_new0 (CDMenuItemData, 1);
471 						g_hash_table_insert (pSsidTable, g_strdup (cSsid), pItemData);
472 					}
473 					else
474 					{
475 						g_free (pItemData->cAccessPoint);
476 					}
477 					pItemData->cDevice = g_strdup (cDevice);
478 					pItemData->iPercent = iPercent;
479 					pItemData->cAccessPoint = g_strdup (cAccessPointPath);
480 					pItemData->cSsid = g_strdup (cSsid);
481 					if (pConnList)
482 					{
483 						int n = GPOINTER_TO_INT (pConnList->data);
484 						pItemData->cConnection = g_strdup (g_ptr_array_index (paConnections, n));
485 					}
486 					cairo_dock_add_in_menu_with_stock_and_data (cSsid, cImage, G_CALLBACK (_on_select_access_point), pMenu, pItemData);
487 				}
488 				else
489 				{
490 					GtkWidget *pSubMenu = cairo_dock_create_sub_menu (cSsid, pMenu, cImage);
491 					GList *c;
492 					for (c = pConnList; c != NULL; c = c->next)
493 					{
494 						int n = GPOINTER_TO_INT (c->data);
495 						GHashTable *h = g_ptr_array_index (paSettings, n);
496 						if (!h)
497 							continue;
498 						GHashTable *hh = g_hash_table_lookup (h, "connection");
499 						if (!hh)
500 							continue;
501 						v = g_hash_table_lookup (hh, "id");
502 						if (v && G_VALUE_HOLDS_STRING (v))
503 						{
504 							const gchar *cID = g_value_get_string (v);
505 
506 							pItemData = g_new0 (CDMenuItemData, 1);
507 							pItemData->cConnection = g_strdup (g_ptr_array_index (paConnections, n));
508 							pItemData->cDevice = g_strdup (cDevice);
509 							pItemData->cAccessPoint = g_strdup (cAccessPointPath);
510 
511 							cairo_dock_add_in_menu_with_stock_and_data (cID, NULL, G_CALLBACK (_on_select_access_point), pSubMenu, GINT_TO_POINTER (n));
512 						}
513 					}
514 				}
515 				g_list_free (pConnList);
516 
517 				g_object_unref (dbus_proxy_AccessPoint_prop);
518 			}
519 			g_ptr_array_free (pAccessPoints, TRUE);
520 		}
521 		else
522 		{
523 			/// si non connecte : ajouter une entree grisee.
524 
525 			/// sinon ajouter une entree pour (des)activer ce device.
526 
527 		}
528 	}
529 	g_ptr_array_free (paDevices, TRUE);
530 	g_ptr_array_free (paConnections, TRUE);
531 	g_hash_table_destroy (pSsidTable);
532 
533 	return pMenu;
534 }
535