transmission 2.83
[tomato.git] / release / src-rt-6.x.4708 / router / transmission / utils / edit.c
blobbf122c4431553f220918e2cb8f8d3600dc6867a7
1 /*
2 * This file Copyright (C) 2012-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: edit.c 14241 2014-01-21 03:10:30Z jordan $
8 */
10 #include <stdio.h> /* fprintf () */
11 #include <string.h> /* strlen (), strstr (), strcmp () */
12 #include <stdlib.h> /* EXIT_FAILURE */
14 #include <event2/buffer.h>
16 #include <libtransmission/transmission.h>
17 #include <libtransmission/tr-getopt.h>
18 #include <libtransmission/utils.h>
19 #include <libtransmission/variant.h>
20 #include <libtransmission/version.h>
22 #define MY_NAME "transmission-edit"
24 static int fileCount = 0;
25 static bool showVersion = false;
26 static const char ** files = NULL;
27 static const char * add = NULL;
28 static const char * deleteme = NULL;
29 static const char * replace[2] = { NULL, NULL };
31 static tr_option options[] =
33 { 'a', "add", "Add a tracker's announce URL", "a", 1, "<url>" },
34 { 'd', "delete", "Delete a tracker's announce URL", "d", 1, "<url>" },
35 { 'r', "replace", "Search and replace a substring in the announce URLs", "r", 1, "<old> <new>" },
36 { 'V', "version", "Show version number and exit", "V", 0, NULL },
37 { 0, NULL, NULL, NULL, 0, NULL }
40 static const char *
41 getUsage (void)
43 return "Usage: " MY_NAME " [options] torrent-file(s)";
46 static int
47 parseCommandLine (int argc, const char ** argv)
49 int c;
50 const char * optarg;
52 while ((c = tr_getopt (getUsage (), argc, argv, options, &optarg)))
54 switch (c)
56 case 'a':
57 add = optarg;
58 break;
60 case 'd':
61 deleteme = optarg;
62 break;
64 case 'r':
65 replace[0] = optarg;
66 c = tr_getopt (getUsage (), argc, argv, options, &optarg);
67 if (c != TR_OPT_UNK)
68 return 1;
69 replace[1] = optarg;
70 break;
72 case 'V':
73 showVersion = true;
74 break;
76 case TR_OPT_UNK:
77 files[fileCount++] = optarg;
78 break;
80 default:
81 return 1;
85 return 0;
88 static bool
89 removeURL (tr_variant * metainfo, const char * url)
91 const char * str;
92 tr_variant * announce_list;
93 bool changed = false;
95 if (tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL) && !strcmp (str, url))
97 printf ("\tRemoved \"%s\" from \"announce\"\n", str);
98 tr_variantDictRemove (metainfo, TR_KEY_announce);
99 changed = true;
102 if (tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list))
104 tr_variant * tier;
105 int tierIndex = 0;
106 while ((tier = tr_variantListChild (announce_list, tierIndex)))
108 tr_variant * node;
109 int nodeIndex = 0;
110 while ((node = tr_variantListChild (tier, nodeIndex)))
112 if (tr_variantGetStr (node, &str, NULL) && !strcmp (str, url))
114 printf ("\tRemoved \"%s\" from \"announce-list\" tier #%d\n", str, (tierIndex+1));
115 tr_variantListRemove (tier, nodeIndex);
116 changed = true;
118 else ++nodeIndex;
121 if (tr_variantListSize (tier) == 0)
123 printf ("\tNo URLs left in tier #%d... removing tier\n", (tierIndex+1));
124 tr_variantListRemove (announce_list, tierIndex);
126 else
128 ++tierIndex;
132 if (tr_variantListSize (announce_list) == 0)
134 printf ("\tNo tiers left... removing announce-list\n");
135 tr_variantDictRemove (metainfo, TR_KEY_announce_list);
139 /* if we removed the "announce" field and there's still another track left,
140 * use it as the "announce" field */
141 if (changed && !tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL))
143 tr_variant * tier;
144 tr_variant * node;
146 if ((tier = tr_variantListChild (announce_list, 0)))
148 if ((node = tr_variantListChild (tier, 0)))
150 if (tr_variantGetStr (node, &str, NULL))
152 tr_variantDictAddStr (metainfo, TR_KEY_announce, str);
153 printf ("\tAdded \"%s\" to announce\n", str);
159 return changed;
162 static char*
163 replaceSubstr (const char * str, const char * in, const char * out)
165 char * walk;
166 struct evbuffer * buf = evbuffer_new ();
167 const size_t inlen = strlen (in);
168 const size_t outlen = strlen (out);
170 while ((walk = strstr (str, in)))
172 evbuffer_add (buf, str, walk-str);
173 evbuffer_add (buf, out, outlen);
174 str = walk + inlen;
177 evbuffer_add (buf, str, strlen (str));
179 return evbuffer_free_to_str (buf);
182 static bool
183 replaceURL (tr_variant * metainfo, const char * in, const char * out)
185 const char * str;
186 tr_variant * announce_list;
187 bool changed = false;
189 if (tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL) && strstr (str, in))
191 char * newstr = replaceSubstr (str, in, out);
192 printf ("\tReplaced in \"announce\": \"%s\" --> \"%s\"\n", str, newstr);
193 tr_variantDictAddStr (metainfo, TR_KEY_announce, newstr);
194 tr_free (newstr);
195 changed = true;
198 if (tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list))
200 tr_variant * tier;
201 int tierCount = 0;
202 while ((tier = tr_variantListChild (announce_list, tierCount++)))
204 tr_variant * node;
205 int nodeCount = 0;
206 while ((node = tr_variantListChild (tier, nodeCount++)))
208 if (tr_variantGetStr (node, &str, NULL) && strstr (str, in))
210 char * newstr = replaceSubstr (str, in, out);
211 printf ("\tReplaced in \"announce-list\" tier %d: \"%s\" --> \"%s\"\n", tierCount, str, newstr);
212 tr_variantFree (node);
213 tr_variantInitStr (node, newstr, -1);
214 tr_free (newstr);
215 changed = true;
221 return changed;
224 static bool
225 announce_list_has_url (tr_variant * announce_list, const char * url)
227 tr_variant * tier;
228 int tierCount = 0;
229 while ((tier = tr_variantListChild (announce_list, tierCount++)))
231 tr_variant * node;
232 const char * str;
233 int nodeCount = 0;
234 while ((node = tr_variantListChild (tier, nodeCount++)))
235 if (tr_variantGetStr (node, &str, NULL) && !strcmp (str, url))
236 return true;
239 return false;
242 static bool
243 addURL (tr_variant * metainfo, const char * url)
245 const char * announce = NULL;
246 tr_variant * announce_list = NULL;
247 bool changed = false;
248 const bool had_announce = tr_variantDictFindStr (metainfo, TR_KEY_announce, &announce, NULL);
249 const bool had_announce_list = tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list);
251 if (!had_announce && !had_announce_list)
253 /* this new tracker is the only one, so add it to "announce"... */
254 printf ("\tAdded \"%s\" in \"announce\"\n", url);
255 tr_variantDictAddStr (metainfo, TR_KEY_announce, url);
256 changed = true;
258 else
260 if (!had_announce_list)
262 announce_list = tr_variantDictAddList (metainfo, TR_KEY_announce_list, 2);
264 if (had_announce)
266 /* we're moving from an 'announce' to an 'announce-list',
267 * so copy the old announce URL to the list */
268 tr_variant * tier = tr_variantListAddList (announce_list, 1);
269 tr_variantListAddStr (tier, announce);
270 changed = true;
274 /* If the user-specified URL isn't in the announce list yet, add it */
275 if (!announce_list_has_url (announce_list, url))
277 tr_variant * tier = tr_variantListAddList (announce_list, 1);
278 tr_variantListAddStr (tier, url);
279 printf ("\tAdded \"%s\" to \"announce-list\" tier %"TR_PRIuSIZE"\n", url, tr_variantListSize (announce_list));
280 changed = true;
284 return changed;
288 main (int argc, char * argv[])
290 int i;
291 int changedCount = 0;
293 files = tr_new0 (const char*, argc);
295 tr_logSetLevel (TR_LOG_ERROR);
297 if (parseCommandLine (argc, (const char**)argv))
298 return EXIT_FAILURE;
300 if (showVersion)
302 fprintf (stderr, MY_NAME" "LONG_VERSION_STRING"\n");
303 return EXIT_SUCCESS;
306 if (fileCount < 1)
308 fprintf (stderr, "ERROR: No torrent files specified.\n");
309 tr_getopt_usage (MY_NAME, getUsage (), options);
310 fprintf (stderr, "\n");
311 return EXIT_FAILURE;
314 if (!add && !deleteme && !replace[0])
316 fprintf (stderr, "ERROR: Must specify -a, -d or -r\n");
317 tr_getopt_usage (MY_NAME, getUsage (), options);
318 fprintf (stderr, "\n");
319 return EXIT_FAILURE;
322 for (i=0; i<fileCount; ++i)
324 tr_variant top;
325 bool changed = false;
326 const char * filename = files[i];
328 printf ("%s\n", filename);
330 if (tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename))
332 printf ("\tError reading file\n");
333 continue;
336 if (deleteme != NULL)
337 changed |= removeURL (&top, deleteme);
339 if (add != NULL)
340 changed = addURL (&top, add);
342 if (replace[0] && replace[1])
343 changed |= replaceURL (&top, replace[0], replace[1]);
345 if (changed)
347 ++changedCount;
348 tr_variantToFile (&top, TR_VARIANT_FMT_BENC, filename);
351 tr_variantFree (&top);
354 printf ("Changed %d files\n", changedCount);
356 tr_free (files);
357 return EXIT_SUCCESS;