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 #include <string.h>
21 #include <stdlib.h>
22 #define __USE_POSIX
23 #include <time.h>
24 #include <glib/gstdio.h>
25 
26 #include "applet-struct.h"
27 #include "applet-dnd2share.h"
28 
29 
cd_dnd2share_free_uploaded_item(CDUploadedItem * pItem)30 void cd_dnd2share_free_uploaded_item (CDUploadedItem *pItem)
31 {
32 	if (pItem == NULL)
33 		return ;
34 	g_strfreev (pItem->cDistantUrls);
35 	g_free (pItem->cItemName);
36 	g_free (pItem->cLocalPath);
37 	g_free (pItem);
38 }
39 
40 
_get_short_text_for_menu(const gchar * cInitText)41 static gchar * _get_short_text_for_menu (const gchar *cInitText)
42 {
43 	if (cInitText == NULL) // the backend should not allow that!
44 		return g_strdup (D_("No text"));
45 
46 	// remove extras withespaces first
47 	gchar *cLongText = g_strstrip (g_strdup (cInitText));
48 	// then print only the first line => no, like Clipper
49 	/*gchar *str = strchr (cLongText, '\n');
50 	if (str)
51 		*str = '\0';*/
52 	gchar *cShortText = cairo_dock_cut_string (cLongText, 40);
53 
54 	// With 'Text' label, it's different than filename
55 	gchar *cResult = g_strdup_printf ("%s %s", D_("Text:"), cShortText);
56 
57 	g_free (cLongText);
58 	g_free (cShortText);
59 
60 	return cResult;
61 }
62 
cd_dnd2share_build_history(void)63 void cd_dnd2share_build_history (void)
64 {
65 	gchar *cConfFilePath = g_strdup_printf ("%s/%s", myData.cWorkingDirPath, "history.conf");
66 	GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
67 	g_free (cConfFilePath);
68 	if (pKeyFile == NULL)  // no history yet.
69 		return ;
70 
71 	gsize length = 0;
72 	gchar **pGroupList = g_key_file_get_groups (pKeyFile, &length);
73 	if (pGroupList == NULL)
74 		return ;
75 
76 	CDUploadedItem *pItem;
77 	int iSiteID, iFileType;
78 	gchar *cItemName;
79 	GString *sUrlKey = g_string_new ("");
80 	GError *erreur = NULL;
81 	int i,j;
82 	for (i = 0; pGroupList[i] != NULL; i ++)
83 	{
84 		cItemName = pGroupList[i];
85 		iSiteID = g_key_file_get_integer (pKeyFile, cItemName, "site", &erreur);
86 		if (erreur != NULL)
87 		{
88 			cd_warning (erreur->message);
89 			g_error_free (erreur);
90 			erreur = NULL;
91 			g_free (cItemName);
92 			continue;
93 		}
94 		if (iSiteID >= CD_NB_SITES_MAX)
95 		{
96 			cd_warning ("dnd2share : this backend doesn't exist !");
97 			g_free (cItemName);
98 			continue;
99 		}
100 		iFileType = g_key_file_get_integer (pKeyFile, cItemName, "type", &erreur);
101 		if (erreur != NULL)
102 		{
103 			cd_warning (erreur->message);
104 			g_error_free (erreur);
105 			erreur = NULL;
106 			g_free (cItemName);
107 			continue;
108 		}
109 		if (iFileType >= CD_NB_FILE_TYPES)
110 		{
111 			cd_warning ("dnd2share : this type of file doesn't exist !");
112 			g_free (cItemName);
113 			continue;
114 		}
115 
116 		pItem = g_new0 (CDUploadedItem, 1);
117 		pItem->cItemName = cItemName;
118 		pItem->iSiteID = iSiteID;
119 		pItem->iFileType = iFileType;
120 		pItem->cDistantUrls = g_new0 (gchar*, myData.backends[iFileType][iSiteID].iNbUrls+1);
121 		for (j = 0; j < myData.backends[iFileType][iSiteID].iNbUrls; j ++)
122 		{
123 			g_string_printf (sUrlKey, "url%d", j);
124 			pItem->cDistantUrls[j] = g_key_file_get_string (pKeyFile, cItemName, sUrlKey->str, NULL);  // NULL if this URL has not been saved before.
125 		}
126 		pItem->iDate = g_key_file_get_integer (pKeyFile, cItemName, "date", NULL);
127 
128 		pItem->cLocalPath = g_key_file_get_string (pKeyFile, cItemName, "local path", NULL);
129 		if (pItem->iFileType == CD_TYPE_TEXT)
130 			pItem->cFileName = _get_short_text_for_menu (pItem->cLocalPath);
131 		else
132 			pItem->cFileName = g_path_get_basename (pItem->cLocalPath);
133 
134 		myData.pUpoadedItems = g_list_prepend (myData.pUpoadedItems, pItem);
135 	}
136 	g_string_free (sUrlKey, TRUE);
137 	g_free (pGroupList);  // the content has been added in the list.
138 	g_key_file_free (pKeyFile);
139 }
140 
cd_dnd2share_clear_history(void)141 void cd_dnd2share_clear_history (void)
142 {
143 	g_list_foreach (myData.pUpoadedItems, (GFunc) cd_dnd2share_free_uploaded_item, NULL);
144 	g_list_free (myData.pUpoadedItems);
145 	myData.pUpoadedItems = NULL;
146 }
147 
148 
149 
_cd_dnd2share_threaded_upload(CDSharedMemory * pSharedMemory)150 static void _cd_dnd2share_threaded_upload (CDSharedMemory *pSharedMemory)
151 {
152 	gchar *cFilePath = pSharedMemory->cCurrentFilePath;
153 
154 	pSharedMemory->cResultUrls = g_new0 (gchar *, pSharedMemory->iNbUrls+1);  // NULL-terminated
155 	pSharedMemory->upload (cFilePath, pSharedMemory->cLocalDir, pSharedMemory->bAnonymous, pSharedMemory->iLimitRate, pSharedMemory->cResultUrls, &pSharedMemory->pError);
156 
157 	if (pSharedMemory->cResultUrls[0] && pSharedMemory->iTinyURLService != 0)  // tiny-url.
158 	{
159 		gchar *Command = NULL;
160 		switch (pSharedMemory->iTinyURLService)
161 		{
162 			case 1:
163 			default:
164 				Command = g_strdup_printf ("http://tinyurl.com/api-create.php?url=%s", pSharedMemory->cResultUrls[0]);
165 			break;
166 			case 2:
167 				Command = g_strdup_printf ("http://shorterlink.org/createlink.php?url=%s", pSharedMemory->cResultUrls[0]);
168 			break;
169 			/*http://soso.bz/
170 			http://notlong.com/links/
171 			http://www.minu.me/
172 			http://cuturl.biz/
173 			http://tiny.cc/
174 			http://o-x.fr/create.php
175 			http://petitlien.fr/create.php
176 			http://bit.ly
177 			http://is.gd/create.php*/
178 		}
179 		pSharedMemory->cResultUrls[pSharedMemory->iNbUrls-1] = cairo_dock_get_url_data (Command, NULL);
180 		g_free (Command);
181 	}
182 }
183 
_cd_dnd2share_show_error_dialog(const gchar * cError)184 static void _cd_dnd2share_show_error_dialog (const gchar *cError)
185 {
186 	gldi_dialogs_remove_on_icon (myIcon);
187 
188 	gldi_dialog_show_temporary_with_icon (cError,
189 		myIcon,
190 		myContainer,
191 		myConfig.dTimeDialogs * 2,
192 		MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
193 }
194 
_cd_dnd2share_update_from_result(CDSharedMemory * pSharedMemory)195 static gboolean _cd_dnd2share_update_from_result (CDSharedMemory *pSharedMemory)
196 {
197 	CD_APPLET_ENTER;
198 	gchar *cFilePath = pSharedMemory->cCurrentFilePath;
199 	if (pSharedMemory->pError != NULL)
200 		_cd_dnd2share_show_error_dialog (pSharedMemory->pError->message);
201 	else if (pSharedMemory->cResultUrls == NULL || pSharedMemory->cResultUrls[0] == NULL) // just to be sure
202 		_cd_dnd2share_show_error_dialog (DND2SHARE_GENERIC_ERROR_MSG);
203 	else
204 	{
205 		CDSiteBackend *pCurrentBackend = myData.pCurrentBackend[pSharedMemory->iCurrentFileType];
206 		// we add it in the history.
207 		if (myConfig.iNbItems != 0)
208 		{
209 			// open the file which contains the history
210 			gchar *cConfFilePath = g_strdup_printf ("%s/%s", myData.cWorkingDirPath, "history.conf");
211 			GKeyFile *pKeyFile;
212 			if (! g_file_test (cConfFilePath, G_FILE_TEST_EXISTS))  // no history yet.
213 				pKeyFile = g_key_file_new ();
214 			else
215 				pKeyFile = cairo_dock_open_key_file (cConfFilePath);
216 			if (pKeyFile == NULL)  // probleme de droit ?
217 			{
218 				cd_warning ("Couldn't add this item to history.");
219 			}
220 			else
221 			{
222 				// we check the size limit
223 				gsize length = 0;
224 				gchar **pGroupList = g_key_file_get_groups (pKeyFile, &length);
225 				if (length == myConfig.iNbItems)  // if yes, we remove the first entry
226 				{
227 					g_key_file_remove_group (pKeyFile, pGroupList[0], NULL);
228 					if (myData.pUpoadedItems != NULL)  // which is the last one in the list
229 					{
230 						GList *it = g_list_last (myData.pUpoadedItems);
231 						if (it->prev != NULL)
232 							it->prev->next = NULL;
233 						it->prev = NULL;
234 						cd_dnd2share_free_uploaded_item (it->data);
235 						g_list_free1 (it);
236 					}
237 				}
238 				g_strfreev (pGroupList);
239 
240 				// we add the new item at the end of the file
241 				time_t iDate = time (NULL);
242 				gchar *cItemName = g_strdup_printf ("item_%ld", iDate);
243 
244 				g_key_file_set_integer (pKeyFile, cItemName, "site", myConfig.iPreferedSite[pSharedMemory->iCurrentFileType]);
245 				g_key_file_set_integer (pKeyFile, cItemName, "date", iDate);
246 				g_key_file_set_integer (pKeyFile, cItemName, "type", pSharedMemory->iCurrentFileType);
247 				GString *sUrlKey = g_string_new ("");
248 				int j;
249 				for (j = 0; j < pCurrentBackend->iNbUrls; j ++)
250 				{
251 					g_string_printf (sUrlKey, "url%d", j);
252 					g_key_file_set_string (pKeyFile, cItemName, sUrlKey->str, pSharedMemory->cResultUrls[j]);
253 				}
254 				g_key_file_set_string (pKeyFile, cItemName, "local path", cFilePath);
255 
256 				// and at the beginning of the list
257 				CDUploadedItem *pItem = g_new0 (CDUploadedItem, 1);
258 				pItem->cItemName = cItemName;
259 				pItem->iSiteID = myConfig.iPreferedSite[pSharedMemory->iCurrentFileType];
260 				pItem->iFileType = pSharedMemory->iCurrentFileType;
261 				pItem->cDistantUrls = g_new0 (gchar*, pCurrentBackend->iNbUrls + 1);
262 				for (j = 0; j < pCurrentBackend->iNbUrls; j ++)
263 				{
264 					pItem->cDistantUrls[j] = g_strdup (pSharedMemory->cResultUrls[j]);
265 				}
266 				pItem->iDate = iDate;
267 				pItem->cLocalPath = g_strdup (cFilePath);
268 				if (pItem->iFileType == CD_TYPE_TEXT)
269 					pItem->cFileName = _get_short_text_for_menu (cFilePath);
270 				else
271 					pItem->cFileName = g_path_get_basename (cFilePath);
272 				myData.pUpoadedItems = g_list_prepend (myData.pUpoadedItems, pItem);
273 
274 				// We flush the file.
275 				cairo_dock_write_keys_to_file (pKeyFile, cConfFilePath);
276 				g_key_file_free (pKeyFile);
277 				g_string_free (sUrlKey, TRUE);
278 
279 				// we keep a copy if it's an image
280 				if (myConfig.bkeepCopy && pSharedMemory->iCurrentFileType == CD_TYPE_IMAGE)
281 				{
282 					gchar *cCommand = g_strdup_printf ("cp '%s' '%s/%s'", cFilePath, myData.cWorkingDirPath, cItemName);
283 					int r = system (cCommand);
284 					if (r < 0)
285 						cd_warning ("Not able to launch this command: %s", cCommand);
286 					g_free (cCommand);
287 				}
288 			}
289 			g_free (cConfFilePath);
290 		}
291 
292 		// We copy the url to the clipboard
293 		gchar *cURL = NULL;
294 		if (myConfig.bUseTinyAsDefault)
295 			cURL = pSharedMemory->cResultUrls[pCurrentBackend->iNbUrls-1];
296 		if (cURL == NULL)
297 			cURL = pSharedMemory->cResultUrls[pCurrentBackend->iPreferedUrlType];
298 		if (cURL == NULL)
299 		{
300 			int i;
301 			for (i = 0; i < pCurrentBackend->iNbUrls && cURL == NULL; i ++)
302 			{
303 				cURL = pSharedMemory->cResultUrls[i];
304 			}
305 		}
306 		cd_dnd2share_copy_url_to_clipboard (cURL);
307 
308 		// we keep the last URL if we don't want the history.
309 		g_free (myData.cLastURL);
310 		myData.cLastURL = g_strdup (cURL);
311 		myData.iCurrentItemNum = 0;
312 
313 		// we can now display a dialogue.
314 		if (myConfig.bEnableDialogs || myDesklet)
315 		{
316 			gldi_dialogs_remove_on_icon (myIcon);
317 			gldi_dialog_show_temporary_with_icon (D_("File has been uploaded.\nJust press CTRL+v to paste its URL anywhere."),
318 				myIcon,
319 				myContainer,
320 				myConfig.dTimeDialogs,
321 				MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
322 		}
323 
324 		// and set the image on the icon.
325 		if (myConfig.bDisplayLastImage)
326 		{
327 			if (pSharedMemory->iCurrentFileType == CD_TYPE_IMAGE)
328 				CD_APPLET_SET_IMAGE_ON_MY_ICON (cFilePath);
329 			else
330 				CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
331 		}
332 	}
333 
334 	// stop the animation.
335 	CD_APPLET_STOP_DEMANDING_ATTENTION;
336 
337 	// delete the file if it was a temporary one.
338 	if (pSharedMemory->bTempFile)
339 	{
340 		g_remove (pSharedMemory->cCurrentFilePath);
341 	}
342 
343 	if (myData.cTmpFilePath != NULL)
344 	{
345 		g_remove (myData.cTmpFilePath);
346 		g_free (myData.cTmpFilePath);
347 		myData.cTmpFilePath = NULL;
348 	}
349 
350 	gldi_task_discard (myData.pTask);
351 	myData.pTask = NULL;
352 	CD_APPLET_LEAVE (FALSE);
353 }
_free_shared_memory(CDSharedMemory * pSharedMemory)354 static void _free_shared_memory (CDSharedMemory *pSharedMemory)
355 {
356 	g_free (pSharedMemory->cLocalDir);
357 	g_free (pSharedMemory->cCurrentFilePath);
358 	g_strfreev (pSharedMemory->cResultUrls);
359 	if (pSharedMemory->pError != NULL)
360 		g_error_free (pSharedMemory->pError);
361 	g_free (pSharedMemory);
362 }
363 #define CD_BUFFER_LENGTH 50
cd_dnd2share_launch_upload(const gchar * cFilePath,CDFileType iFileType)364 void cd_dnd2share_launch_upload (const gchar *cFilePath, CDFileType iFileType)
365 {
366 	if (myData.pTask != NULL)
367 	{
368 		cd_warning ("Please wait the current upload is finished before starting a new one.");
369 		gldi_dialogs_remove_on_icon (myIcon);
370 		gldi_dialog_show_temporary_with_icon (D_("Please wait for the current upload to finish before starting a new one."),
371 			myIcon,
372 			myContainer,
373 			myConfig.dTimeDialogs,
374 			MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
375 		return ;
376 	}
377 
378 	if (myData.pCurrentBackend[iFileType]->upload == NULL)
379 	{
380 		cd_warning ("sorry, it's still not possible to upload this type of file");
381 		return ;
382 	}
383 
384 	// launch the task.
385 	CDSharedMemory *pSharedMemory = g_new0 (CDSharedMemory, 1);
386 	gboolean bIsPath = FALSE; // we can receive text or a text file
387 	if (strncmp (cFilePath, "file://", 7) == 0)
388 	{
389 		cd_debug ("FilePath: %s", cFilePath);
390 		cFilePath += 7;
391 		bIsPath = TRUE;
392 	}
393 	else if (iFileType == CD_TYPE_TEXT && *cFilePath == '/' && g_file_test (cFilePath, G_FILE_TEST_EXISTS))
394 		bIsPath = TRUE;
395 
396 	gchar *cTmpFile = NULL;
397 	if (myConfig.bUseOnlyFileType)
398 	{
399 		// for a piece of text, write it in a temporary file and upload this one.
400 		if (iFileType == CD_TYPE_TEXT && ! bIsPath)
401 		{
402 			// make a filename based on the upload date.
403 			cTmpFile = g_new0 (gchar, CD_BUFFER_LENGTH+1);
404 			time_t epoch = time (NULL);
405 			struct tm currentTime;
406 			localtime_r (&epoch, &currentTime);
407 			strftime (cTmpFile, CD_BUFFER_LENGTH, "/tmp/cd-%F__%H-%M-%S.txt", &currentTime);
408 
409 			// write the text inside.
410 			g_file_set_contents (cTmpFile,
411 				cFilePath,
412 				-1,
413 				NULL);
414 
415 			// upload this file
416 			cFilePath = cTmpFile;
417 			pSharedMemory->bTempFile = TRUE;
418 		}
419 		// force the 'file' type to be used.
420 		pSharedMemory->iCurrentFileType = CD_TYPE_FILE;
421 	}
422 	else
423 	{
424 		pSharedMemory->iCurrentFileType = iFileType;
425 	}
426 
427 	// If we drop a text file, we have an URI but we want to post the content to a website
428 	if (pSharedMemory->iCurrentFileType == CD_TYPE_TEXT && bIsPath)
429 	{
430 		cd_debug ("Type is text and it's a file: %s", cFilePath);
431 		gchar *cContents = NULL;
432 		gsize iLength;
433 		g_file_get_contents (cFilePath, &cContents, &iLength, NULL);
434 		if (cContents == NULL)  // file was not readable, abort.
435 		{
436 			cd_warning ("file not readable !");
437 			gldi_dialogs_remove_on_icon (myIcon);
438 			gldi_dialog_show_temporary_with_icon (D_("This file is not readable."),
439 				myIcon,
440 				myContainer,
441 				myConfig.dTimeDialogs,
442 				MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
443 			return ;
444 		}
445 		pSharedMemory->cCurrentFilePath = cContents;
446 	}
447 	else
448 		pSharedMemory->cCurrentFilePath = g_strdup (cFilePath);
449 
450 	g_free (cTmpFile);
451 
452 	pSharedMemory->iTinyURLService = myConfig.iTinyURLService;
453 	pSharedMemory->cLocalDir = g_strdup (myConfig.cLocalDir);
454 	pSharedMemory->bAnonymous = myConfig.bAnonymous;
455 	pSharedMemory->iLimitRate = myConfig.iLimitRate;
456 
457 	CDSiteBackend *pCurrentBackend = myData.pCurrentBackend[pSharedMemory->iCurrentFileType];
458 	g_return_if_fail (pCurrentBackend != NULL);
459 	pSharedMemory->upload = pCurrentBackend->upload;
460 	pSharedMemory->iNbUrls = pCurrentBackend->iNbUrls;
461 
462 	myData.pTask = gldi_task_new_full (0,  // 1 shot task.
463 		(GldiGetDataAsyncFunc) _cd_dnd2share_threaded_upload,
464 		(GldiUpdateSyncFunc) _cd_dnd2share_update_from_result,
465 		(GFreeFunc) _free_shared_memory,
466 		pSharedMemory);
467 
468 	gldi_task_launch (myData.pTask);
469 
470 	CD_APPLET_DEMANDS_ATTENTION (myConfig.cIconAnimation, 1e6);  // we'll stop it later, at the end of the upload.
471 }
472 
473 
474 
cd_dnd2share_clear_working_directory(void)475 void cd_dnd2share_clear_working_directory (void)
476 {
477 	g_return_if_fail (myData.cWorkingDirPath != NULL && *myData.cWorkingDirPath == '/');
478 	gchar *cCommand = g_strdup_printf ("rm -rf '%s'/*", myData.cWorkingDirPath);
479 	int r = system (cCommand);
480 	if (r < 0)
481 		cd_warning ("Not able to launch this command: %s", cCommand);
482 	g_free (cCommand);
483 
484 	gchar *cConfFilePath = g_strdup_printf ("%s/%s", myData.cWorkingDirPath, "history.conf");
485 	g_file_set_contents (cConfFilePath, "#dnd2share's history\n\n", -1, NULL);
486 	g_free (cConfFilePath);
487 
488 	if (myConfig.bDisplayLastImage)
489 	{
490 		CD_APPLET_SET_IMAGE_ON_MY_ICON (MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE);
491 	}
492 }
493 
494 
cd_dnd2share_clear_copies_in_working_directory(void)495 void cd_dnd2share_clear_copies_in_working_directory (void)
496 {
497 	g_return_if_fail (myData.cWorkingDirPath != NULL && *myData.cWorkingDirPath == '/');
498 	gchar *cCommand = g_strdup_printf ("find '%s' -mindepth 1 ! -name *.conf -exec rm -f '{}' \\;", myData.cWorkingDirPath);
499 	int r = system (cCommand);
500 	if (r < 0)
501 		cd_warning ("Not able to launch this command: %s", cCommand);
502 	g_free (cCommand);
503 }
504 
cd_dnd2share_set_working_directory_size(guint iNbItems)505 void cd_dnd2share_set_working_directory_size (guint iNbItems)
506 {
507 	gchar *cConfFilePath = g_strdup_printf ("%s/%s", myData.cWorkingDirPath, "history.conf");
508 	GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
509 	if (pKeyFile == NULL)  // no history yet
510 	{
511 		g_free (cConfFilePath);
512 		return ;
513 	}
514 
515 	gsize length = 0;
516 	gchar **pGroupList = g_key_file_get_groups (pKeyFile, &length);
517 	if (length > iNbItems)
518 	{
519 		gchar *cItemName;
520 		GString *sPreviewPath = g_string_new ("");
521 		guint i;
522 		for (i = 0; pGroupList[i] != NULL && i < length - iNbItems; i ++)  // we remove all extras groups and the preview
523 		{
524 			cItemName = pGroupList[i];
525 			g_string_printf (sPreviewPath, "%s/%s", myData.cWorkingDirPath, cItemName);
526 			g_remove (sPreviewPath->str);
527 			g_key_file_remove_group (pKeyFile, cItemName, NULL);
528 		}
529 		cairo_dock_write_keys_to_file (pKeyFile, cConfFilePath);
530 		g_string_free (sPreviewPath, TRUE);
531 	}
532 
533 	g_strfreev (pGroupList);
534 	g_key_file_free (pKeyFile);
535 	g_free (cConfFilePath);
536 }
537 
cd_dnd2share_clean_working_directory(void)538 void cd_dnd2share_clean_working_directory (void)
539 {
540 	if (myConfig.iNbItems == 0)  // no more history => clean the working directory.
541 	{
542 		cd_debug ("DND2SHARE : Pas d'historique -> On efface le contenu de '%s'", myData.cWorkingDirPath);
543 		cd_dnd2share_clear_working_directory ();
544 	}
545 	else
546 	{
547 		cd_dnd2share_set_working_directory_size (myConfig.iNbItems);  // we remove extras items.
548 		if (! myConfig.bkeepCopy)  // we don't want a copy of the images
549 		{
550 			cd_debug ("DND2SHARE : Pas de copies locales -> On efface les images de '%s'", myData.cWorkingDirPath);
551 			cd_dnd2share_clear_copies_in_working_directory ();
552 		}
553 	}
554 }
555 
556 
cd_dnd2share_copy_url_to_clipboard(const gchar * cURL)557 void cd_dnd2share_copy_url_to_clipboard (const gchar *cURL)
558 {
559 	GtkClipboard *pClipBoard;
560 	pClipBoard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
561 	gtk_clipboard_set_text (pClipBoard, cURL, -1);
562 }
cd_dnd2share_copy_url_to_primary(const gchar * cURL)563 void cd_dnd2share_copy_url_to_primary (const gchar *cURL)
564 {
565 	GtkClipboard *pClipBoard;
566 	pClipBoard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
567 	gtk_clipboard_set_text (pClipBoard, cURL, -1);
568 }
569 
cd_dnd2share_get_prefered_url_from_item(CDUploadedItem * pItem)570 gchar *cd_dnd2share_get_prefered_url_from_item (CDUploadedItem *pItem)
571 {
572 	CDSiteBackend *pBackend = &myData.backends[pItem->iFileType][pItem->iSiteID];
573 	//g_print ("%s (type:%d; site:%d)\n", __func__, pItem->iFileType, pItem->iSiteID);
574 	gchar *cURL = NULL;
575 	if (myConfig.bUseTinyAsDefault)
576 		cURL = pItem->cDistantUrls[pBackend->iNbUrls-1];
577 	if (cURL == NULL)
578 		cURL = pItem->cDistantUrls[pBackend->iPreferedUrlType];
579 	if (cURL == NULL)
580 	{
581 		int i;
582 		for (i = 0; i < pBackend->iNbUrls && cURL == NULL; i ++)
583 		{
584 			cURL = pItem->cDistantUrls[i];
585 		}
586 	}
587 	return cURL;
588 }
589 
cd_dnd2share_set_current_url_from_item(CDUploadedItem * pItem)590 void cd_dnd2share_set_current_url_from_item (CDUploadedItem *pItem)
591 {
592 	gchar *cURL = cd_dnd2share_get_prefered_url_from_item (pItem);
593 	g_free (myData.cLastURL);
594 	myData.cLastURL = g_strdup (cURL);
595 
596 	int i = 0;
597 	GList *it;
598 	for (it = myData.pUpoadedItems; it != NULL; it = it->next)
599 	{
600 		if (it->data == pItem)
601 			break ;
602 		i ++;
603 	}
604 	myData.iCurrentItemNum = i;
605 }
606 
607 
cd_dnd2share_remove_one_item(CDUploadedItem * pItem)608 void cd_dnd2share_remove_one_item (CDUploadedItem *pItem)
609 {
610 	g_return_if_fail (pItem != NULL);
611 
612 	// we remove the corresponding group in the history file
613 	gchar *cConfFilePath = g_strdup_printf ("%s/%s", myData.cWorkingDirPath, "history.conf");
614 	if (! g_file_test (cConfFilePath, G_FILE_TEST_EXISTS))  // no history yet.
615 		return;
616 
617 	GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
618 	if (pKeyFile == NULL)  // right problem?
619 	{
620 		cd_warning ("Couldn't remove this item from history.");
621 		return ;
622 	}
623 
624 	g_key_file_remove_group (pKeyFile, pItem->cItemName, NULL);
625 	cairo_dock_write_keys_to_file (pKeyFile, cConfFilePath);
626 	g_key_file_free (pKeyFile);
627 	g_free (cConfFilePath);
628 
629 	// we remove the local copy.
630 	gchar *cPreviewPath = g_strdup_printf ("%s/%s", myData.cWorkingDirPath, pItem->cItemName);
631 	g_remove (cPreviewPath);
632 	g_free (cPreviewPath);
633 
634 	// If it's the current item, switch to the next one.
635 	if (myData.pUpoadedItems && myData.pUpoadedItems->data == pItem)
636 	{
637 		g_free (myData.cLastURL);
638 		myData.cLastURL = NULL;
639 		myData.iCurrentItemNum = 0;
640 		if (myData.pUpoadedItems->next != NULL)
641 		{
642 			CDUploadedItem *pNextItem = myData.pUpoadedItems->next->data;
643 			gchar *cURL = cd_dnd2share_get_prefered_url_from_item (pNextItem);
644 			myData.cLastURL = g_strdup (cURL);
645 		}
646 	}
647 
648 	// We remove the item from the list
649 	myData.pUpoadedItems = g_list_remove (myData.pUpoadedItems, pItem);
650 	cd_dnd2share_free_uploaded_item (pItem);
651 }
652 
653 
cd_dnd2share_register_new_backend(CDFileType iFileType,const gchar * cSiteName,int iNbUrls,const gchar ** cUrlLabels,int iPreferedUrlType,CDUploadFunc pUploadFunc)654 void cd_dnd2share_register_new_backend (CDFileType iFileType, const gchar *cSiteName, int iNbUrls, const gchar **cUrlLabels, int iPreferedUrlType, CDUploadFunc pUploadFunc)
655 {
656 	int iNumSite = myData.iNbSitesForType[iFileType];
657 	CDSiteBackend *pNewBackend = &myData.backends[iFileType][iNumSite];
658 	myData.iNbSitesForType[iFileType] ++;
659 
660 	pNewBackend->cSiteName = cSiteName;
661 	pNewBackend->iNbUrls = iNbUrls + 1;  // +1 for tiny-url.
662 	pNewBackend->cUrlLabels = g_new0 (gchar *, pNewBackend->iNbUrls+1);  // +1 for end NULL.
663 	memcpy (pNewBackend->cUrlLabels, cUrlLabels, iNbUrls * sizeof (gchar*));  // we take N first labels given by the backend.
664 	pNewBackend->cUrlLabels[iNbUrls] = D_("Tiny URL");  // + tiny-url.
665 	pNewBackend->iPreferedUrlType = iPreferedUrlType;
666 	pNewBackend->upload = pUploadFunc;
667 }
668