Merge lp:~kriomant/do-plugins/transmission into lp:do-plugins

Proposed by kriomant
Status: Merged
Merged at revision: 754
Proposed branch: lp:~kriomant/do-plugins/transmission
Merge into: lp:do-plugins
Diff against target: 2699 lines (+2488/-0) (has conflicts)
30 files modified
.bzrignore (+9/-0)
DoPlugins.mds (+4/-0)
Makefile.am (+1/-0)
Transmission/Makefile.am (+40/-0)
Transmission/Resources/Transmission.addin.xml.in (+37/-0)
Transmission/Transmission.mdp (+64/-0)
Transmission/gtk-gui/Transmission.TransmissionConfig.cs (+161/-0)
Transmission/gtk-gui/generated.cs (+82/-0)
Transmission/gtk-gui/gui.stetic (+196/-0)
Transmission/src/Config/TransmissionConfig.cs (+91/-0)
Transmission/src/ITorrentEntry.cs (+16/-0)
Transmission/src/JsonCollectionImporter.cs (+117/-0)
Transmission/src/TorrentAbstractLimitSpeedAction.cs (+80/-0)
Transmission/src/TorrentDirectoryItem.cs (+64/-0)
Transmission/src/TorrentFileItem.cs (+97/-0)
Transmission/src/TorrentFileSetPriorityAction.cs (+108/-0)
Transmission/src/TorrentItem.cs (+72/-0)
Transmission/src/TorrentItemSource.cs (+130/-0)
Transmission/src/TorrentLimitDownloadSpeedAction.cs (+47/-0)
Transmission/src/TorrentLimitUploadSpeedAction.cs (+47/-0)
Transmission/src/TorrentMarkForDownloadAction.cs (+62/-0)
Transmission/src/TorrentOperateAction.cs (+37/-0)
Transmission/src/TorrentStartAction.cs (+42/-0)
Transmission/src/TorrentStopAction.cs (+42/-0)
Transmission/src/TorrentUnmarkForDownloadAction.cs (+62/-0)
Transmission/src/TorrentVerifyAction.cs (+42/-0)
Transmission/src/TransmissionAPI.cs (+575/-0)
Transmission/src/TransmissionPlugin.cs (+50/-0)
Transmission/src/Utils.cs (+111/-0)
configure.ac (+2/-0)
Text conflict in .bzrignore
To merge this branch: bzr merge lp:~kriomant/do-plugins/transmission
Reviewer Review Type Date Requested Status
Chris Halse Rogers Needs Fixing
Review via email: mp+30966@code.launchpad.net

Description of the change

Transmission plug-in.

Allows to control Transmission torrent client using XML-RPC API. Supports starting and stopping torrent downloads, choosing files to download, setting speed limits.

To post a comment you must log in.
Revision history for this message
Chris Halse Rogers (raof) wrote :

Oh, wow. Sorry for missing this for so long!

This looks good. I've only got two minor niggles, and one larger one. The two minor ones are: you should have copyright headers on the files you've created, and I'd generally use a lot more automatic properties rather than explicit private _foo variables.

The major one is that it bundles a binary copy of Jayrock.Json. We generally try to minimise the binaries we bundle in the source tree; most distributions will not accept packages with binaries bundled like this.

Given the terrible length of time that this has been waiting for a review, I'm happy to make these changes myself if you don't want to. I would like your email address, though, so that I can credit you in the Authors file properly.

review: Needs Fixing
Revision history for this message
kriomant (kriomant) wrote :

On 11 Dec 2011 10:16, "Chris Halse Rogers" <email address hidden> wrote:
>
> Review: Needs Fixing
>
> Oh, wow. Sorry for missing this for so long!

I thought development is completely stalled.

> This looks good. I've only got two minor niggles, and one larger one.
 The two minor ones are: you should have copyright headers on the files
you've created, and I'd generally use a lot more automatic properties
rather than explicit private _foo variables.
>
> The major one is that it bundles a binary copy of Jayrock.Json. We
generally try to minimise the binaries we bundle in the source tree; most
distributions will not accept packages with binaries bundled like this.

How will you solve this? I haven't found JSON library for Mono in standard
Ubuntu distribution. Will you include source code of Jayrock?

> Given the terrible length of time that this has been waiting for a
review, I'm happy to make these changes myself if you don't want to. I
would like your email address, though, so that I can credit you in the
Authors file properly.

It would be good.
My address is "Mikhail Trishchenkov <email address hidden>"

One more question: should I write wiki page?

> --
> https://code.launchpad.net/~kriomant/do-plugins/transmission/+merge/30966
> You are the owner of lp:~kriomant/do-plugins/transmission.

Revision history for this message
Chris Halse Rogers (raof) wrote :

I wouldn't bother writing a wiki page; I plan to take the wiki down, as it's become a hive of spam and villany and I don't have time to curate it properly.

I'll transfer the documentation into a local format, so it can be installed alongside the plugins. Once I've got that set up, you might want to add documentation there.

As for the JSON library, I'll see if Hyena.Json does what needs to be done here. If not, I'll grab the Jayrock source code and package it.

Revision history for this message
kriomant (kriomant) wrote :

Is there any progress?

Revision history for this message
Chris Halse Rogers (raof) wrote :

On Tue, 2012-01-10 at 17:33 +0000, kriomant wrote:
> Is there any progress?

Not on this, sorry. I'm slowly working my way through the blocker bugs
for the next core release. I hope to have that done this week or early
next week.

After I've done that I'll be able to work on plugins stuff, of which
this will be the first priority.

Revision history for this message
kriomant (kriomant) wrote :

Bump

Revision history for this message
kriomant (kriomant) wrote :

I have an impression that "this week" have already passed...

Revision history for this message
Chris Halse Rogers (raof) wrote :

The longest week ever has ended!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2010-06-29 08:19:20 +0000
3+++ .bzrignore 2010-07-26 16:47:47 +0000
4@@ -1,3 +1,4 @@
5+<<<<<<< TREE
6 Makefile.in
7 Makefile
8 *.pc
9@@ -23,3 +24,11 @@
10 *.addin.xml
11 *.gmo
12 m4/intltool.m4
13+=======
14+Emesene.addin.xml
15+Transmission/Makefile
16+Transmission/Makefile.in
17+Transmission/Transmission.pidb
18+Transmission/bin
19+Transmission/Resources/Transmission.addin.xml
20+>>>>>>> MERGE-SOURCE
21
22=== modified file 'DoPlugins.mds'
23--- DoPlugins.mds 2009-11-08 23:58:01 +0000
24+++ DoPlugins.mds 2010-07-26 16:47:47 +0000
25@@ -78,6 +78,7 @@
26 <Entry build="True" name="Baconator" configuration="Debug" />
27 <Entry build="True" name="Chromium" configuration="Debug" />
28 <Entry build="True" name="GNOME-Calculator" configuration="Debug" />
29+ <Entry build="True" name="Transmission" configuration="Debug" />
30 </Configuration>
31 <Configuration name="Release" ctype="CombineConfiguration">
32 <Entry build="True" name="Rhythmbox" configuration="Release" />
33@@ -157,6 +158,7 @@
34 <Entry build="True" name="Baconator" configuration="Release" />
35 <Entry build="True" name="Chromium" configuration="Release" />
36 <Entry build="True" name="GNOME-Calculator" configuration="Release" />
37+ <Entry build="True" name="Transmission" configuration="Release" />
38 </Configuration>
39 </Configurations>
40 <StartMode startupentry="Rhythmbox" single="True">
41@@ -237,6 +239,7 @@
42 <Execute type="None" entry="Baconator" />
43 <Execute type="None" entry="Chromium" />
44 <Execute type="None" entry="GNOME-Calculator" />
45+ <Execute type="None" entry="Transmission" />
46 </StartMode>
47 <MonoDevelop.ChangeLogAddIn.ChangeLogInfo policy="UpdateNearestChangeLog" />
48 <Entries>
49@@ -317,5 +320,6 @@
50 <Entry filename="Baconator/Baconator.mdp" />
51 <Entry filename="Chromium/Chromium.mdp" />
52 <Entry filename="GNOME-Calculator/GNOME-Calculator.mdp" />
53+ <Entry filename="Transmission/Transmission.mdp" />
54 </Entries>
55 </Combine>
56\ No newline at end of file
57
58=== modified file 'Makefile.am'
59--- Makefile.am 2009-11-08 23:58:01 +0000
60+++ Makefile.am 2010-07-26 16:47:47 +0000
61@@ -70,6 +70,7 @@
62 TinyUrl \
63 Tracker \
64 Translate \
65+ Transmission \
66 Tomboy \
67 Vinagre \
68 VirtualBox \
69
70=== added directory 'Transmission'
71=== added file 'Transmission/Makefile.am'
72--- Transmission/Makefile.am 1970-01-01 00:00:00 +0000
73+++ Transmission/Makefile.am 2010-07-26 16:47:47 +0000
74@@ -0,0 +1,40 @@
75+include $(top_srcdir)/build.rules.mk
76+
77+ASSEMBLY=Transmission
78+
79+FILES = \
80+ gtk-gui/Transmission.TransmissionConfig.cs \
81+ gtk-gui/generated.cs \
82+ src/Config/TransmissionConfig.cs \
83+ src/ITorrentEntry.cs \
84+ src/JsonCollectionImporter.cs \
85+ src/Utils.cs \
86+ src/TorrentDirectoryItem.cs \
87+ src/TorrentFileItem.cs \
88+ src/TorrentFileSetPriorityAction.cs \
89+ src/TorrentItem.cs \
90+ src/TorrentItemSource.cs \
91+ src/TorrentAbstractLimitSpeedAction.cs \
92+ src/TorrentLimitDownloadSpeedAction.cs \
93+ src/TorrentLimitUploadSpeedAction.cs \
94+ src/TorrentMarkForDownloadAction.cs \
95+ src/TorrentStartAction.cs \
96+ src/TorrentStopAction.cs \
97+ src/TorrentUnmarkForDownloadAction.cs \
98+ src/TorrentVerifyAction.cs \
99+ src/TorrentOperateAction.cs \
100+ src/TransmissionAPI.cs \
101+ src/TransmissionPlugin.cs
102+
103+RESOURCES = \
104+ Resources/Transmission.addin.xml \
105+ gtk-gui/gui.stetic \
106+ Resources/icons/transmission.png
107+
108+REFERENCES = \
109+ System \
110+ System.Core \
111+ lib/Jayrock.Json.dll \
112+ $(DO_PLATFORM_LINUX_LIBS) \
113+ $(DO_UNIVERSE_LIBS) \
114+ $(GTK_SHARP_20_LIBS)
115
116=== added directory 'Transmission/Resources'
117=== added file 'Transmission/Resources/Transmission.addin.xml.in'
118--- Transmission/Resources/Transmission.addin.xml.in 1970-01-01 00:00:00 +0000
119+++ Transmission/Resources/Transmission.addin.xml.in 2010-07-26 16:47:47 +0000
120@@ -0,0 +1,37 @@
121+<Addin
122+ id="Transmission"
123+ namespace="Do"
124+ version="0.1"
125+ name="Transmission"
126+ description="Control Transmission torrent client."
127+ author="Mikhail Trishchenkov"
128+ category="Community"
129+ defaultEnabled="true"
130+ url="http://do.davebsd.com/wiki/Transmission_Plugin"
131+ >
132+
133+ <Runtime>
134+ <Import assembly="Transmission.dll"/>
135+ </Runtime>
136+
137+ <!--Localizer type="Gettext" catalog="gnome-do-plugins" location="@expanded_datadir@/locale" /-->
138+
139+ <Dependencies>
140+ <Addin id="Universe" version="1.0" />
141+ </Dependencies>
142+
143+ <Extension path="/Do/ItemSource">
144+ <ItemSource type="Transmission.TorrentItemSource" />
145+ </Extension>
146+ <Extension path="/Do/Action">
147+ <Action type="Transmission.TorrentStopAction" />
148+ <Action type="Transmission.TorrentStartAction" />
149+ <Action type="Transmission.TorrentVerifyAction" />
150+ <Action type="Transmission.TorrentLimitDownloadSpeedAction" />
151+ <Action type="Transmission.TorrentLimitUploadSpeedAction" />
152+ <Action type="Transmission.TorrentFileSetPriorityAction" />
153+ <Action type="Transmission.TorrentMarkForDownloadAction" />
154+ <Action type="Transmission.TorrentUnmarkForDownloadAction" />
155+ <Action type="Transmission.TorrentOperateAction" />
156+ </Extension>
157+</Addin>
158
159=== added directory 'Transmission/Resources/icons'
160=== added file 'Transmission/Resources/icons/transmission.png'
161Binary files Transmission/Resources/icons/transmission.png 1970-01-01 00:00:00 +0000 and Transmission/Resources/icons/transmission.png 2010-07-26 16:47:47 +0000 differ
162=== added file 'Transmission/Transmission.mdp'
163--- Transmission/Transmission.mdp 1970-01-01 00:00:00 +0000
164+++ Transmission/Transmission.mdp 2010-07-26 16:47:47 +0000
165@@ -0,0 +1,64 @@
166+<Project name="Transmission" fileversion="2.0" DefaultNamespace="Transmission" language="C#" targetFramework="3.5" ctype="DotNetProject">
167+ <Configurations active="Debug">
168+ <Configuration name="Debug" ctype="DotNetProjectConfiguration">
169+ <Output directory="bin/Debug" assembly="Transmission" />
170+ <Build debugmode="True" target="Library" />
171+ <Execution consolepause="True" runwithwarnings="True" runtime="MsNet" />
172+ <CodeGeneration compiler="Mcs" warninglevel="4" optimize="False" unsafecodeallowed="False" generateoverflowchecks="False" definesymbols="DEBUG" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
173+ </Configuration>
174+ <Configuration name="Release" ctype="DotNetProjectConfiguration">
175+ <Output directory="bin/Release" assembly="Transmission" />
176+ <Build debugmode="False" target="Library" />
177+ <Execution consolepause="True" runwithwarnings="True" runtime="MsNet" />
178+ <CodeGeneration compiler="Mcs" warninglevel="4" optimize="False" unsafecodeallowed="False" generateoverflowchecks="False" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
179+ </Configuration>
180+ </Configurations>
181+ <Contents>
182+ <File subtype="Directory" buildaction="Compile" name="src" />
183+ <File subtype="Directory" buildaction="Compile" name="Resources" />
184+ <File subtype="Code" buildaction="Nothing" name="Resources/Transmission.addin.xml" />
185+ <File subtype="Code" buildaction="EmbedAsResource" name="gtk-gui/gui.stetic" />
186+ <File subtype="Code" buildaction="Compile" name="gtk-gui/generated.cs" />
187+ <File subtype="Code" buildaction="Compile" name="gtk-gui/Transmission.TransmissionConfig.cs" />
188+ <File subtype="Code" buildaction="Compile" name="src/Config/TransmissionConfig.cs" />
189+ <File subtype="Directory" buildaction="Compile" name="Resources/icons" />
190+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-add.png" />
191+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-remove.png" />
192+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-revisions.png" />
193+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-share.png" />
194+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-start.png" />
195+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-stop.png" />
196+ <File subtype="Code" buildaction="Nothing" name="Resources/icons/transmission-web.png" />
197+ <File subtype="Code" buildaction="Compile" name="src/ITorrentEntry.cs" />
198+ <File subtype="Code" buildaction="Compile" name="src/JsonCollectionImporter.cs" />
199+ <File subtype="Code" buildaction="Compile" name="src/TorrentDirectoryItem.cs" />
200+ <File subtype="Code" buildaction="Compile" name="src/TorrentFileItem.cs" />
201+ <File subtype="Code" buildaction="Compile" name="src/TorrentFileSetPriorityAction.cs" />
202+ <File subtype="Code" buildaction="Compile" name="src/TorrentItem.cs" />
203+ <File subtype="Code" buildaction="Compile" name="src/TorrentItemSource.cs" />
204+ <File subtype="Code" buildaction="Compile" name="src/TorrentAbstractLimitSpeedAction.cs" />
205+ <File subtype="Code" buildaction="Compile" name="src/TorrentLimitDownloadSpeedAction.cs" />
206+ <File subtype="Code" buildaction="Compile" name="src/TorrentMarkForDownloadAction.cs" />
207+ <File subtype="Code" buildaction="Compile" name="src/TorrentStartAction.cs" />
208+ <File subtype="Code" buildaction="Compile" name="src/TorrentStopAction.cs" />
209+ <File subtype="Code" buildaction="Compile" name="src/TorrentUnmarkForDownloadAction.cs" />
210+ <File subtype="Code" buildaction="Compile" name="src/TorrentVerifyAction.cs" />
211+ <File subtype="Code" buildaction="Compile" name="src/TransmissionAPI.cs" />
212+ <File subtype="Code" buildaction="Compile" name="src/TransmissionPlugin.cs" />
213+ <File subtype="Code" buildaction="Compile" name="src/Utils.cs" />
214+ <File subtype="Code" buildaction="Compile" name="src/TorrentLimitUploadSpeedAction.cs" />
215+ <File subtype="Code" buildaction="Compile" name="src/TorrentOperateAction.cs" />
216+ </Contents>
217+ <References>
218+ <ProjectReference type="Gac" localcopy="True" refto="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
219+ <ProjectReference type="Gac" localcopy="True" refto="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
220+ <ProjectReference type="Gac" localcopy="True" refto="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
221+ <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
222+ <ProjectReference type="Gac" localcopy="True" refto="Mono.Addins, Version=0.4.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
223+ <ProjectReference type="Gac" localcopy="True" refto="Do.Platform, Version=0.9.0.0, Culture=neutral" />
224+ <ProjectReference type="Gac" localcopy="True" refto="Do.Universe, Version=0.9.0.0, Culture=neutral" />
225+ <ProjectReference type="Gac" localcopy="True" refto="Do.Platform.Linux, Version=0.9.0.0, Culture=neutral" />
226+ <ProjectReference type="Assembly" localcopy="True" specificVersion="False" refto="lib/Jayrock.Json.dll" />
227+ </References>
228+ <GtkDesignInfo gettextClass="Mono.Addins.AddinManager.CurrentLocalizer" />
229+</Project>
230\ No newline at end of file
231
232=== added directory 'Transmission/gtk-gui'
233=== added file 'Transmission/gtk-gui/Transmission.TransmissionConfig.cs'
234--- Transmission/gtk-gui/Transmission.TransmissionConfig.cs 1970-01-01 00:00:00 +0000
235+++ Transmission/gtk-gui/Transmission.TransmissionConfig.cs 2010-07-26 16:47:47 +0000
236@@ -0,0 +1,161 @@
237+// ------------------------------------------------------------------------------
238+// <autogenerated>
239+// This code was generated by a tool.
240+//
241+//
242+// Changes to this file may cause incorrect behavior and will be lost if
243+// the code is regenerated.
244+// </autogenerated>
245+// ------------------------------------------------------------------------------
246+
247+namespace Transmission {
248+
249+
250+ public partial class TransmissionConfig {
251+
252+ private Gtk.Alignment alignment108;
253+
254+ private Gtk.Table table1;
255+
256+ private Gtk.HBox hbox1;
257+
258+ private Gtk.Entry address_entry;
259+
260+ private Gtk.Label remote_port_label;
261+
262+ private Gtk.Entry port_entry;
263+
264+ private Gtk.Label label1;
265+
266+ private Gtk.Label label2;
267+
268+ private Gtk.Label label3;
269+
270+ private Gtk.Entry password_entry;
271+
272+ private Gtk.Entry user_name_entry;
273+
274+ protected virtual void Build() {
275+ Stetic.Gui.Initialize(this);
276+ // Widget Transmission.TransmissionConfig
277+ Stetic.BinContainer.Attach(this);
278+ this.Name = "Transmission.TransmissionConfig";
279+ // Container child Transmission.TransmissionConfig.Gtk.Container+ContainerChild
280+ this.alignment108 = new Gtk.Alignment(0.5F, 0F, 1F, 0F);
281+ this.alignment108.Name = "alignment108";
282+ // Container child alignment108.Gtk.Container+ContainerChild
283+ this.table1 = new Gtk.Table(((uint)(3)), ((uint)(2)), false);
284+ this.table1.Name = "table1";
285+ this.table1.RowSpacing = ((uint)(6));
286+ this.table1.ColumnSpacing = ((uint)(6));
287+ // Container child table1.Gtk.Table+TableChild
288+ this.hbox1 = new Gtk.HBox();
289+ this.hbox1.Name = "hbox1";
290+ this.hbox1.Spacing = 6;
291+ // Container child hbox1.Gtk.Box+BoxChild
292+ this.address_entry = new Gtk.Entry();
293+ this.address_entry.CanFocus = true;
294+ this.address_entry.Name = "address_entry";
295+ this.address_entry.IsEditable = true;
296+ this.address_entry.InvisibleChar = '●';
297+ this.hbox1.Add(this.address_entry);
298+ Gtk.Box.BoxChild w1 = ((Gtk.Box.BoxChild)(this.hbox1[this.address_entry]));
299+ w1.Position = 0;
300+ // Container child hbox1.Gtk.Box+BoxChild
301+ this.remote_port_label = new Gtk.Label();
302+ this.remote_port_label.Name = "remote_port_label";
303+ this.remote_port_label.LabelProp = Mono.Addins.AddinManager.CurrentLocalizer.GetString("Port");
304+ this.hbox1.Add(this.remote_port_label);
305+ Gtk.Box.BoxChild w2 = ((Gtk.Box.BoxChild)(this.hbox1[this.remote_port_label]));
306+ w2.Position = 1;
307+ w2.Expand = false;
308+ w2.Fill = false;
309+ // Container child hbox1.Gtk.Box+BoxChild
310+ this.port_entry = new Gtk.Entry();
311+ this.port_entry.CanFocus = true;
312+ this.port_entry.Name = "port_entry";
313+ this.port_entry.IsEditable = true;
314+ this.port_entry.WidthChars = 5;
315+ this.port_entry.MaxLength = 5;
316+ this.port_entry.InvisibleChar = '●';
317+ this.hbox1.Add(this.port_entry);
318+ Gtk.Box.BoxChild w3 = ((Gtk.Box.BoxChild)(this.hbox1[this.port_entry]));
319+ w3.Position = 2;
320+ w3.Expand = false;
321+ this.table1.Add(this.hbox1);
322+ Gtk.Table.TableChild w4 = ((Gtk.Table.TableChild)(this.table1[this.hbox1]));
323+ w4.LeftAttach = ((uint)(1));
324+ w4.RightAttach = ((uint)(2));
325+ w4.YOptions = ((Gtk.AttachOptions)(4));
326+ // Container child table1.Gtk.Table+TableChild
327+ this.label1 = new Gtk.Label();
328+ this.label1.Name = "label1";
329+ this.label1.Xalign = 0F;
330+ this.label1.LabelProp = Mono.Addins.AddinManager.CurrentLocalizer.GetString("_Address");
331+ this.label1.UseUnderline = true;
332+ this.table1.Add(this.label1);
333+ Gtk.Table.TableChild w5 = ((Gtk.Table.TableChild)(this.table1[this.label1]));
334+ w5.XOptions = ((Gtk.AttachOptions)(4));
335+ w5.YOptions = ((Gtk.AttachOptions)(4));
336+ // Container child table1.Gtk.Table+TableChild
337+ this.label2 = new Gtk.Label();
338+ this.label2.Name = "label2";
339+ this.label2.Xalign = 0F;
340+ this.label2.LabelProp = Mono.Addins.AddinManager.CurrentLocalizer.GetString("_Password");
341+ this.label2.UseUnderline = true;
342+ this.table1.Add(this.label2);
343+ Gtk.Table.TableChild w6 = ((Gtk.Table.TableChild)(this.table1[this.label2]));
344+ w6.TopAttach = ((uint)(2));
345+ w6.BottomAttach = ((uint)(3));
346+ w6.XOptions = ((Gtk.AttachOptions)(4));
347+ w6.YOptions = ((Gtk.AttachOptions)(4));
348+ // Container child table1.Gtk.Table+TableChild
349+ this.label3 = new Gtk.Label();
350+ this.label3.Name = "label3";
351+ this.label3.Xalign = 0F;
352+ this.label3.LabelProp = Mono.Addins.AddinManager.CurrentLocalizer.GetString("_Login");
353+ this.label3.UseUnderline = true;
354+ this.table1.Add(this.label3);
355+ Gtk.Table.TableChild w7 = ((Gtk.Table.TableChild)(this.table1[this.label3]));
356+ w7.TopAttach = ((uint)(1));
357+ w7.BottomAttach = ((uint)(2));
358+ w7.XOptions = ((Gtk.AttachOptions)(4));
359+ w7.YOptions = ((Gtk.AttachOptions)(4));
360+ // Container child table1.Gtk.Table+TableChild
361+ this.password_entry = new Gtk.Entry();
362+ this.password_entry.CanFocus = true;
363+ this.password_entry.Name = "password_entry";
364+ this.password_entry.IsEditable = true;
365+ this.password_entry.Visibility = false;
366+ this.password_entry.InvisibleChar = '●';
367+ this.table1.Add(this.password_entry);
368+ Gtk.Table.TableChild w8 = ((Gtk.Table.TableChild)(this.table1[this.password_entry]));
369+ w8.TopAttach = ((uint)(2));
370+ w8.BottomAttach = ((uint)(3));
371+ w8.LeftAttach = ((uint)(1));
372+ w8.RightAttach = ((uint)(2));
373+ w8.YOptions = ((Gtk.AttachOptions)(4));
374+ // Container child table1.Gtk.Table+TableChild
375+ this.user_name_entry = new Gtk.Entry();
376+ this.user_name_entry.CanFocus = true;
377+ this.user_name_entry.Name = "user_name_entry";
378+ this.user_name_entry.IsEditable = true;
379+ this.user_name_entry.InvisibleChar = '●';
380+ this.table1.Add(this.user_name_entry);
381+ Gtk.Table.TableChild w9 = ((Gtk.Table.TableChild)(this.table1[this.user_name_entry]));
382+ w9.TopAttach = ((uint)(1));
383+ w9.BottomAttach = ((uint)(2));
384+ w9.LeftAttach = ((uint)(1));
385+ w9.RightAttach = ((uint)(2));
386+ w9.YOptions = ((Gtk.AttachOptions)(4));
387+ this.alignment108.Add(this.table1);
388+ this.Add(this.alignment108);
389+ if ((this.Child != null)) {
390+ this.Child.ShowAll();
391+ }
392+ this.Hide();
393+ this.user_name_entry.Changed += new System.EventHandler(this.OnUserNameEntryChanged);
394+ this.password_entry.Changed += new System.EventHandler(this.OnPasswordEntryChanged);
395+ }
396+ }
397+}
398
399=== added file 'Transmission/gtk-gui/generated.cs'
400--- Transmission/gtk-gui/generated.cs 1970-01-01 00:00:00 +0000
401+++ Transmission/gtk-gui/generated.cs 2010-07-26 16:47:47 +0000
402@@ -0,0 +1,82 @@
403+// ------------------------------------------------------------------------------
404+// <autogenerated>
405+// This code was generated by a tool.
406+//
407+//
408+// Changes to this file may cause incorrect behavior and will be lost if
409+// the code is regenerated.
410+// </autogenerated>
411+// ------------------------------------------------------------------------------
412+
413+namespace Stetic {
414+
415+
416+ internal class Gui {
417+
418+ private static bool initialized;
419+
420+ internal static void Initialize(Gtk.Widget iconRenderer) {
421+ if ((Stetic.Gui.initialized == false)) {
422+ Stetic.Gui.initialized = true;
423+ }
424+ }
425+ }
426+
427+ internal class BinContainer {
428+
429+ private Gtk.Widget child;
430+
431+ private Gtk.UIManager uimanager;
432+
433+ public static BinContainer Attach(Gtk.Bin bin) {
434+ BinContainer bc = new BinContainer();
435+ bin.SizeRequested += new Gtk.SizeRequestedHandler(bc.OnSizeRequested);
436+ bin.SizeAllocated += new Gtk.SizeAllocatedHandler(bc.OnSizeAllocated);
437+ bin.Added += new Gtk.AddedHandler(bc.OnAdded);
438+ return bc;
439+ }
440+
441+ private void OnSizeRequested(object sender, Gtk.SizeRequestedArgs args) {
442+ if ((this.child != null)) {
443+ args.Requisition = this.child.SizeRequest();
444+ }
445+ }
446+
447+ private void OnSizeAllocated(object sender, Gtk.SizeAllocatedArgs args) {
448+ if ((this.child != null)) {
449+ this.child.Allocation = args.Allocation;
450+ }
451+ }
452+
453+ private void OnAdded(object sender, Gtk.AddedArgs args) {
454+ this.child = args.Widget;
455+ }
456+
457+ public void SetUiManager(Gtk.UIManager uim) {
458+ this.uimanager = uim;
459+ this.child.Realized += new System.EventHandler(this.OnRealized);
460+ }
461+
462+ private void OnRealized(object sender, System.EventArgs args) {
463+ if ((this.uimanager != null)) {
464+ Gtk.Widget w;
465+ w = this.child.Toplevel;
466+ if (((w != null) && typeof(Gtk.Window).IsInstanceOfType(w))) {
467+ ((Gtk.Window)(w)).AddAccelGroup(this.uimanager.AccelGroup);
468+ this.uimanager = null;
469+ }
470+ }
471+ }
472+ }
473+
474+ internal class ActionGroups {
475+
476+ public static Gtk.ActionGroup GetActionGroup(System.Type type) {
477+ return Stetic.ActionGroups.GetActionGroup(type.FullName);
478+ }
479+
480+ public static Gtk.ActionGroup GetActionGroup(string name) {
481+ return null;
482+ }
483+ }
484+}
485
486=== added file 'Transmission/gtk-gui/gui.stetic'
487--- Transmission/gtk-gui/gui.stetic 1970-01-01 00:00:00 +0000
488+++ Transmission/gtk-gui/gui.stetic 2010-07-26 16:47:47 +0000
489@@ -0,0 +1,196 @@
490+<?xml version="1.0" encoding="utf-8"?>
491+<stetic-interface>
492+ <configuration>
493+ <images-root-path>..</images-root-path>
494+ <target-gtk-version>2.12</target-gtk-version>
495+ </configuration>
496+ <import>
497+ <widget-library name="Do.Platform.Linux, Version=0.9.0.0, Culture=neutral" />
498+ <widget-library name="../bin/Debug/Transmission.dll" internal="true" />
499+ </import>
500+ <widget class="Gtk.Bin" id="Transmission.TransmissionConfig" design-size="444 300">
501+ <property name="MemberName" />
502+ <property name="Visible">False</property>
503+ <child>
504+ <widget class="Gtk.Alignment" id="alignment108">
505+ <property name="MemberName" />
506+ <property name="Yscale">0</property>
507+ <property name="Yalign">0</property>
508+ <child>
509+ <widget class="Gtk.Table" id="table1">
510+ <property name="MemberName" />
511+ <property name="NRows">3</property>
512+ <property name="NColumns">2</property>
513+ <property name="RowSpacing">6</property>
514+ <property name="ColumnSpacing">6</property>
515+ <child>
516+ <widget class="Gtk.HBox" id="hbox1">
517+ <property name="MemberName" />
518+ <property name="Spacing">6</property>
519+ <child>
520+ <widget class="Gtk.Entry" id="address_entry">
521+ <property name="MemberName" />
522+ <property name="CanFocus">True</property>
523+ <property name="IsEditable">True</property>
524+ <property name="InvisibleChar">●</property>
525+ </widget>
526+ <packing>
527+ <property name="Position">0</property>
528+ <property name="AutoSize">True</property>
529+ </packing>
530+ </child>
531+ <child>
532+ <widget class="Gtk.Label" id="remote_port_label">
533+ <property name="MemberName">remote_port_label</property>
534+ <property name="LabelProp" translatable="yes">Port</property>
535+ </widget>
536+ <packing>
537+ <property name="Position">1</property>
538+ <property name="AutoSize">True</property>
539+ <property name="Expand">False</property>
540+ <property name="Fill">False</property>
541+ </packing>
542+ </child>
543+ <child>
544+ <widget class="Gtk.Entry" id="port_entry">
545+ <property name="MemberName">port_entry</property>
546+ <property name="CanFocus">True</property>
547+ <property name="IsEditable">True</property>
548+ <property name="WidthChars">5</property>
549+ <property name="MaxLength">5</property>
550+ <property name="InvisibleChar">●</property>
551+ </widget>
552+ <packing>
553+ <property name="Position">2</property>
554+ <property name="AutoSize">False</property>
555+ <property name="Expand">False</property>
556+ </packing>
557+ </child>
558+ </widget>
559+ <packing>
560+ <property name="LeftAttach">1</property>
561+ <property name="RightAttach">2</property>
562+ <property name="AutoSize">True</property>
563+ <property name="YOptions">Fill</property>
564+ <property name="XExpand">True</property>
565+ <property name="XFill">True</property>
566+ <property name="XShrink">False</property>
567+ <property name="YExpand">False</property>
568+ <property name="YFill">True</property>
569+ <property name="YShrink">False</property>
570+ </packing>
571+ </child>
572+ <child>
573+ <widget class="Gtk.Label" id="label1">
574+ <property name="MemberName" />
575+ <property name="Xalign">0</property>
576+ <property name="LabelProp" translatable="yes">_Address</property>
577+ <property name="UseUnderline">True</property>
578+ </widget>
579+ <packing>
580+ <property name="AutoSize">True</property>
581+ <property name="XOptions">Fill</property>
582+ <property name="YOptions">Fill</property>
583+ <property name="XExpand">False</property>
584+ <property name="XFill">True</property>
585+ <property name="XShrink">False</property>
586+ <property name="YExpand">False</property>
587+ <property name="YFill">True</property>
588+ <property name="YShrink">False</property>
589+ </packing>
590+ </child>
591+ <child>
592+ <widget class="Gtk.Label" id="label2">
593+ <property name="MemberName" />
594+ <property name="Xalign">0</property>
595+ <property name="LabelProp" translatable="yes">_Password</property>
596+ <property name="UseUnderline">True</property>
597+ </widget>
598+ <packing>
599+ <property name="TopAttach">2</property>
600+ <property name="BottomAttach">3</property>
601+ <property name="AutoSize">True</property>
602+ <property name="XOptions">Fill</property>
603+ <property name="YOptions">Fill</property>
604+ <property name="XExpand">False</property>
605+ <property name="XFill">True</property>
606+ <property name="XShrink">False</property>
607+ <property name="YExpand">False</property>
608+ <property name="YFill">True</property>
609+ <property name="YShrink">False</property>
610+ </packing>
611+ </child>
612+ <child>
613+ <widget class="Gtk.Label" id="label3">
614+ <property name="MemberName" />
615+ <property name="Xalign">0</property>
616+ <property name="LabelProp" translatable="yes">_Login</property>
617+ <property name="UseUnderline">True</property>
618+ </widget>
619+ <packing>
620+ <property name="TopAttach">1</property>
621+ <property name="BottomAttach">2</property>
622+ <property name="AutoSize">True</property>
623+ <property name="XOptions">Fill</property>
624+ <property name="YOptions">Fill</property>
625+ <property name="XExpand">False</property>
626+ <property name="XFill">True</property>
627+ <property name="XShrink">False</property>
628+ <property name="YExpand">False</property>
629+ <property name="YFill">True</property>
630+ <property name="YShrink">False</property>
631+ </packing>
632+ </child>
633+ <child>
634+ <widget class="Gtk.Entry" id="password_entry">
635+ <property name="MemberName" />
636+ <property name="CanFocus">True</property>
637+ <property name="IsEditable">True</property>
638+ <property name="Visibility">False</property>
639+ <property name="InvisibleChar">●</property>
640+ <signal name="Changed" handler="OnPasswordEntryChanged" />
641+ </widget>
642+ <packing>
643+ <property name="TopAttach">2</property>
644+ <property name="BottomAttach">3</property>
645+ <property name="LeftAttach">1</property>
646+ <property name="RightAttach">2</property>
647+ <property name="AutoSize">True</property>
648+ <property name="YOptions">Fill</property>
649+ <property name="XExpand">True</property>
650+ <property name="XFill">True</property>
651+ <property name="XShrink">False</property>
652+ <property name="YExpand">False</property>
653+ <property name="YFill">True</property>
654+ <property name="YShrink">False</property>
655+ </packing>
656+ </child>
657+ <child>
658+ <widget class="Gtk.Entry" id="user_name_entry">
659+ <property name="MemberName" />
660+ <property name="CanFocus">True</property>
661+ <property name="IsEditable">True</property>
662+ <property name="InvisibleChar">●</property>
663+ <signal name="Changed" handler="OnUserNameEntryChanged" />
664+ </widget>
665+ <packing>
666+ <property name="TopAttach">1</property>
667+ <property name="BottomAttach">2</property>
668+ <property name="LeftAttach">1</property>
669+ <property name="RightAttach">2</property>
670+ <property name="AutoSize">True</property>
671+ <property name="YOptions">Fill</property>
672+ <property name="XExpand">True</property>
673+ <property name="XFill">True</property>
674+ <property name="XShrink">False</property>
675+ <property name="YExpand">False</property>
676+ <property name="YFill">True</property>
677+ <property name="YShrink">False</property>
678+ </packing>
679+ </child>
680+ </widget>
681+ </child>
682+ </widget>
683+ </child>
684+ </widget>
685+</stetic-interface>
686\ No newline at end of file
687
688=== added directory 'Transmission/lib'
689=== added file 'Transmission/lib/Jayrock.Json.dll'
690Binary files Transmission/lib/Jayrock.Json.dll 1970-01-01 00:00:00 +0000 and Transmission/lib/Jayrock.Json.dll 2010-07-26 16:47:47 +0000 differ
691=== added file 'Transmission/lib/Jayrock.Json.pdb'
692Binary files Transmission/lib/Jayrock.Json.pdb 1970-01-01 00:00:00 +0000 and Transmission/lib/Jayrock.Json.pdb 2010-07-26 16:47:47 +0000 differ
693=== added directory 'Transmission/src'
694=== added directory 'Transmission/src/Config'
695=== added file 'Transmission/src/Config/TransmissionConfig.cs'
696--- Transmission/src/Config/TransmissionConfig.cs 1970-01-01 00:00:00 +0000
697+++ Transmission/src/Config/TransmissionConfig.cs 2010-07-26 16:47:47 +0000
698@@ -0,0 +1,91 @@
699+using System;
700+using System.IO;
701+using System.Text;
702+
703+using Mono.Addins;
704+
705+using Gtk;
706+
707+using Do.Platform;
708+
709+namespace Transmission
710+{
711+
712+ [System.ComponentModel.Category("File")]
713+ [System.ComponentModel.ToolboxItem(true)]
714+ public partial class TransmissionConfig : Gtk.Bin
715+ {
716+ public static string home_path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
717+ public static string settings_path = System.IO.Path.Combine (home_path, ".config/transmission/settings.json");
718+
719+ static IPreferences prefs;
720+
721+ public TransmissionConfig()
722+ {
723+ Build();
724+ RefreshView();
725+ }
726+
727+ private void RefreshView()
728+ {
729+ address_entry.Text = Address;
730+ port_entry.Text = Port.ToString();
731+ user_name_entry.Text = UserName;
732+ password_entry.Text = Password;
733+ }
734+
735+ static TransmissionConfig()
736+ {
737+ prefs = Services.Preferences.Get<TransmissionConfig>();
738+ }
739+
740+ public static string Address
741+ {
742+ get { return prefs.Get<string>("Address", "127.0.0.1"); }
743+ set { prefs.Set<string> ("Address", value); }
744+ }
745+
746+ public static int Port
747+ {
748+ get { return prefs.Get<int>("Port", TransmissionAPI.DEFAULT_PORT); }
749+ set { prefs.Set<int> ("Port", value); }
750+ }
751+
752+ public static string UserName
753+ {
754+ get { return prefs.Get<string>("UserName", ""); }
755+ set { prefs.Set<string> ("UserName", value); }
756+ }
757+
758+ public static string Password
759+ {
760+ get { return prefs.Get<string>("Password", ""); }
761+ set { prefs.Set<string> ("Password", value); }
762+ }
763+
764+ protected virtual void OnAddressEntryChanged (object sender, System.EventArgs e)
765+ {
766+ Address = address_entry.Text;
767+ TransmissionPlugin.ResetConnection();
768+ }
769+
770+ protected virtual void OnUserNameEntryChanged (object sender, System.EventArgs e)
771+ {
772+ UserName = user_name_entry.Text;
773+ TransmissionPlugin.ResetConnection();
774+ }
775+
776+ protected virtual void OnPasswordEntryChanged (object sender, System.EventArgs e)
777+ {
778+ Password = password_entry.Text;
779+ TransmissionPlugin.ResetConnection();
780+ }
781+
782+ protected virtual void OnPortEntryChanged (object sender, System.EventArgs e)
783+ {
784+ Port = int.Parse(port_entry.Text);
785+ TransmissionPlugin.ResetConnection();
786+ }
787+
788+ }
789+}
790
791=== added file 'Transmission/src/ITorrentEntry.cs'
792--- Transmission/src/ITorrentEntry.cs 1970-01-01 00:00:00 +0000
793+++ Transmission/src/ITorrentEntry.cs 2010-07-26 16:47:47 +0000
794@@ -0,0 +1,16 @@
795+using System.Collections.Generic;
796+
797+namespace Transmission {
798+
799+ public interface ITorrentEntry {
800+ // Owner torrent.
801+ TorrentItem Torrent { get; }
802+
803+ // Path on FS.
804+ string Path { get; }
805+
806+ // Get all files under this entry (recursively).
807+ // For files return file itself.
808+ IEnumerable<TorrentFileItem> GetFiles();
809+ }
810+}
811
812=== added file 'Transmission/src/JsonCollectionImporter.cs'
813--- Transmission/src/JsonCollectionImporter.cs 1970-01-01 00:00:00 +0000
814+++ Transmission/src/JsonCollectionImporter.cs 2010-07-26 16:47:47 +0000
815@@ -0,0 +1,117 @@
816+namespace Transmission
817+{
818+ #region Imports
819+
820+ using System;
821+ using System.Collections.Generic;
822+ using System.Diagnostics;
823+ using Jayrock.Json;
824+ using Jayrock.Json.Conversion;
825+ using Jayrock.Json.Conversion.Converters;
826+
827+ #endregion
828+
829+ /// <summary>
830+ /// An abstract base class for importer implementations that can import
831+ /// a concrete collection instance from a JSON array.
832+ /// </summary>
833+
834+
835+ public abstract class CollectionImporterBase : ImporterBase
836+ {
837+ private readonly Type _elementType;
838+
839+
840+ public CollectionImporterBase(Type outputType, Type elementType) :
841+ base(outputType)
842+ {
843+ if (elementType == null) throw new ArgumentNullException("elementType");
844+
845+ _elementType = elementType;
846+ }
847+
848+
849+ public Type ElementType
850+ {
851+ get { return _elementType; }
852+ }
853+
854+
855+ protected override object ImportFromArray(ImportContext context, JsonReader reader)
856+ {
857+ if (context == null) throw new ArgumentNullException("context");
858+ if (reader == null) throw new ArgumentNullException("reader");
859+
860+
861+ object collection = CreateCollection();
862+
863+
864+ reader.ReadToken(JsonTokenClass.Array);
865+
866+
867+ ImportElements(collection, context, reader);
868+
869+
870+ if (reader.TokenClass != JsonTokenClass.EndArray)
871+ throw new Exception("Implementation error.");
872+
873+
874+ reader.Read();
875+ return collection;
876+ }
877+
878+
879+ protected abstract object CreateCollection();
880+ protected abstract void ImportElements(object collection, ImportContext context, JsonReader reader);
881+ }
882+
883+
884+ /// <summary>
885+ /// An importer for importing a collection of elements from a JSON array.
886+ /// </summary>
887+
888+
889+ public class CollectionImporter<Collection, Element> : CollectionImporterBase
890+ where Collection : ICollection<Element>, new()
891+ {
892+ public CollectionImporter() :
893+ base(typeof(Collection), typeof(Element)) { }
894+
895+
896+ protected override object CreateCollection()
897+ {
898+ return new Collection();
899+ }
900+
901+
902+ protected override void ImportElements(object collection, ImportContext context, JsonReader reader)
903+ {
904+ if (collection == null) throw new ArgumentNullException("collection");
905+ if (context == null) throw new ArgumentNullException("context");
906+ if (reader == null) throw new ArgumentNullException("reader");
907+
908+
909+ ImportElements((ICollection<Element>) collection, context, reader);
910+ }
911+
912+
913+ private static void ImportElements(ICollection<Element> collection, ImportContext context, JsonReader reader)
914+ {
915+ Debug.Assert(collection != null);
916+ Debug.Assert(context != null);
917+ Debug.Assert(reader != null);
918+
919+
920+ while (reader.TokenClass != JsonTokenClass.EndArray)
921+ collection.Add((Element) context.Import(typeof(Element), reader));
922+ }
923+ }
924+
925+ /// <summary>
926+ /// Imports <see cref="List{T}"/> from a JSON array.
927+ /// </summary>
928+
929+ public class ListImporter<T> : CollectionImporter<List<T>, T>
930+ where T : new() { }
931+
932+}
933\ No newline at end of file
934
935=== added file 'Transmission/src/TorrentAbstractLimitSpeedAction.cs'
936--- Transmission/src/TorrentAbstractLimitSpeedAction.cs 1970-01-01 00:00:00 +0000
937+++ Transmission/src/TorrentAbstractLimitSpeedAction.cs 2010-07-26 16:47:47 +0000
938@@ -0,0 +1,80 @@
939+
940+using System;
941+using System.Linq;
942+using System.Collections.Generic;
943+using System.Text.RegularExpressions;
944+
945+using Mono.Addins;
946+
947+using Do.Platform;
948+using Do.Universe;
949+
950+namespace Transmission {
951+
952+ public abstract class TorrentAbstractLimitSpeedAction: Act {
953+
954+ public override IEnumerable<Type> SupportedItemTypes {
955+ get { yield return typeof (TorrentItem); }
956+ }
957+
958+ public override IEnumerable<Type> SupportedModifierItemTypes {
959+ get {
960+ yield return typeof (ITextItem);
961+ yield return typeof (PredefinedSpeed);
962+ }
963+ }
964+
965+ public override bool ModifierItemsOptional {
966+ get { return false; }
967+ }
968+
969+ protected abstract PredefinedSpeed GetCurrentSpeedItem(TorrentItem torrent);
970+
971+ public override IEnumerable<Item> DynamicModifierItemsForItem(Item item) {
972+ TorrentItem torrent = (TorrentItem)item;
973+
974+ yield return new PredefinedSpeed(0, "Unlimited", "Turn download speed limit off");
975+ yield return GetCurrentSpeedItem(torrent);
976+ foreach (PredefinedSpeed speed in Utils.PredefinedSpeedItems)
977+ yield return speed;
978+ }
979+
980+ protected abstract void SetSpeedLimit(TransmissionAPI api, IEnumerable<TorrentItem> torrents, int speed);
981+
982+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
983+ int? speed = null;
984+
985+ // Get speed item, it can be either ITextItem or PredefinedSpeed.
986+ Item modItem = modItems.First();
987+ if (modItem is PredefinedSpeed) {
988+ speed = ((PredefinedSpeed)modItem).Value;
989+ } else {
990+ string speed_str = ((ITextItem)modItem).Text;
991+
992+ try {
993+ // Try to parse entered speed value.
994+ speed = Utils.ParseSpeed(speed_str);
995+
996+ } catch (ArgumentException) {
997+ Log<TransmissionPlugin>.Debug("Invalid speed string: {0}", speed_str);
998+
999+ // Show notification about invalid speed value with some hints on
1000+ // accepted formats.
1001+ string message = AddinManager.CurrentLocalizer.GetString(
1002+ "Can't recognize \"{0}\" as speed\nUse values like: 100k, 50 kb, 20m, 10 mib"
1003+ );
1004+ Services.Notifications.Notify("Transmission", string.Format(message, speed_str), "transmission");
1005+ }
1006+ }
1007+
1008+ // If speed is recognized successfully, set speed limit and update item.
1009+ if (speed.HasValue) {
1010+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1011+ IEnumerable<TorrentItem> torrents = items.Cast<TorrentItem>();
1012+ SetSpeedLimit(api, torrents, speed.Value);
1013+ }
1014+
1015+ yield break;
1016+ }
1017+ }
1018+}
1019
1020=== added file 'Transmission/src/TorrentDirectoryItem.cs'
1021--- Transmission/src/TorrentDirectoryItem.cs 1970-01-01 00:00:00 +0000
1022+++ Transmission/src/TorrentDirectoryItem.cs 2010-07-26 16:47:47 +0000
1023@@ -0,0 +1,64 @@
1024+
1025+using System;
1026+using System.Collections.Generic;
1027+
1028+using Do.Universe;
1029+
1030+namespace Transmission {
1031+
1032+ public class TorrentDirectoryItem: Item, ITorrentEntry {
1033+
1034+ private TorrentItem _torrent;
1035+ private TorrentDirectoryItem _parent;
1036+ private string _name;
1037+ private IList<Item> _files;
1038+
1039+ public TorrentDirectoryItem(TorrentItem torrent, TorrentDirectoryItem parent, string name) {
1040+ _torrent = torrent;
1041+ _parent = parent;
1042+ _name = name;
1043+ _files = new List<Item>();
1044+ }
1045+
1046+ public TorrentItem Torrent {
1047+ get { return _torrent; }
1048+ }
1049+
1050+ public IEnumerable<TorrentFileItem> GetFiles() {
1051+ foreach (ITorrentEntry entry in _files)
1052+ foreach (TorrentFileItem file in entry.GetFiles())
1053+ yield return file;
1054+ }
1055+
1056+ public override string Name {
1057+ get { return _name; }
1058+ }
1059+
1060+ public override string Description {
1061+ get { return string.Empty; }
1062+ }
1063+
1064+ public override string Icon {
1065+ get { return "folder"; }
1066+ }
1067+
1068+ public IList<Item> Files {
1069+ get { return _files; }
1070+ }
1071+
1072+ public string Path {
1073+ get {
1074+ if (_parent != null) {
1075+ return _parent.Path + '/' + _name;
1076+ } else {
1077+ return _name;
1078+ }
1079+ }
1080+ }
1081+
1082+ public string Uri {
1083+ get { return "file://" + Path; }
1084+ }
1085+ }
1086+
1087+}
1088
1089=== added file 'Transmission/src/TorrentFileItem.cs'
1090--- Transmission/src/TorrentFileItem.cs 1970-01-01 00:00:00 +0000
1091+++ Transmission/src/TorrentFileItem.cs 2010-07-26 16:47:47 +0000
1092@@ -0,0 +1,97 @@
1093+
1094+using System;
1095+using System.Collections.Generic;
1096+
1097+using Do.Universe;
1098+
1099+namespace Transmission {
1100+
1101+ public class TorrentFileItem: Item, ITorrentEntry {
1102+
1103+ // Owner torrent.
1104+ private TorrentItem _torrent;
1105+ // Position of this file within torrents file list.
1106+ private int _index;
1107+
1108+ private TorrentDirectoryItem _parent;
1109+ private string _name;
1110+ private long _size, _downloaded;
1111+ private bool _wanted;
1112+ private TransmissionAPI.FilePriority _priority;
1113+
1114+ public TorrentFileItem(
1115+ TorrentItem torrent, int index, TorrentDirectoryItem parent,
1116+ string name, TransmissionAPI.TorrentFileInfo info
1117+ ) {
1118+ _torrent = torrent;
1119+ _index = index;
1120+
1121+ _parent = parent;
1122+ _name = name;
1123+ _size = info.Length;
1124+ _downloaded = info.BytesCompleted;
1125+
1126+ _wanted = info.Wanted;
1127+ _priority = info.Priority;
1128+ }
1129+
1130+ public TorrentItem Torrent {
1131+ get { return _torrent; }
1132+ }
1133+
1134+ public int Index {
1135+ get { return _index; }
1136+ }
1137+
1138+ public TransmissionAPI.FilePriority Priority {
1139+ get { return _priority; }
1140+ }
1141+
1142+ public IEnumerable<TorrentFileItem> GetFiles() {
1143+ yield return this;
1144+ }
1145+
1146+ public override string Name {
1147+ get { return _name; }
1148+ }
1149+
1150+ public override string Description {
1151+ get {
1152+ // I don't use special percentage format string, because it rounds
1153+ // value and I don't want to get "100%" until file is really downloaded.
1154+ // High precision isn't needed, because info is mostly out-of-date.
1155+
1156+ if (_downloaded == _size)
1157+ return string.Format("Complete, {0}", Utils.FormatSize(_size));
1158+
1159+ else if (_wanted)
1160+ return string.Format("{0} of {1} complete ({2:0}%)",
1161+ Utils.FormatSize(_downloaded), Utils.FormatSize(_size),
1162+ Math.Floor(100.0 * _downloaded / _size)
1163+ );
1164+
1165+ else if (_downloaded != 0)
1166+ return string.Format("Skipped, {0} of {1} complete ({2:0}%)",
1167+ Utils.FormatSize(_downloaded),Utils.FormatSize(_size),
1168+ Math.Floor(100.0 * _downloaded / _size)
1169+ );
1170+
1171+ else
1172+ return string.Format("Skipped, {0}", Utils.FormatSize(_size));
1173+ }
1174+ }
1175+
1176+ public override string Icon {
1177+ get { return "document"; }
1178+ }
1179+
1180+ public string Path {
1181+ get { return _parent.Path + '/' + _name; }
1182+ }
1183+
1184+ public string Uri {
1185+ get { return "file://" + Path; }
1186+ }
1187+ }
1188+
1189+}
1190
1191=== added file 'Transmission/src/TorrentFileSetPriorityAction.cs'
1192--- Transmission/src/TorrentFileSetPriorityAction.cs 1970-01-01 00:00:00 +0000
1193+++ Transmission/src/TorrentFileSetPriorityAction.cs 2010-07-26 16:47:47 +0000
1194@@ -0,0 +1,108 @@
1195+
1196+using System;
1197+using System.Linq;
1198+using System.Collections.Generic;
1199+
1200+using Mono.Addins;
1201+
1202+using Do.Platform;
1203+using Do.Universe;
1204+
1205+namespace Transmission {
1206+
1207+ public class PriorityItem: Item {
1208+ private TransmissionAPI.FilePriority _value;
1209+ private string _name;
1210+ private string _icon;
1211+
1212+ public PriorityItem(TransmissionAPI.FilePriority value, string name, string icon) {
1213+ _value = value;
1214+ _name = name;
1215+ _icon = icon;
1216+ }
1217+
1218+ public override string Name {
1219+ get { return _name; }
1220+ }
1221+
1222+ public override string Description {
1223+ get { return ""; }
1224+ }
1225+
1226+ public override string Icon {
1227+ get { return _icon; }
1228+ }
1229+
1230+ public TransmissionAPI.FilePriority Value {
1231+ get { return _value; }
1232+ }
1233+ }
1234+
1235+ public class TorrentFileSetPriorityAction: Act {
1236+
1237+ public TorrentFileSetPriorityAction() {
1238+ }
1239+
1240+ public override string Name {
1241+ get { return AddinManager.CurrentLocalizer.GetString ("Set priority"); }
1242+ }
1243+
1244+ public override string Description {
1245+ get { return AddinManager.CurrentLocalizer.GetString ("Set download priority"); }
1246+ }
1247+
1248+ public override string Icon {
1249+ get { return "object-flip-vertical"; }
1250+ }
1251+
1252+ public override IEnumerable<Type> SupportedItemTypes {
1253+ get {
1254+ yield return typeof (ITorrentEntry);
1255+ }
1256+ }
1257+
1258+ public override IEnumerable<Type> SupportedModifierItemTypes {
1259+ get {
1260+ yield return typeof (PriorityItem);
1261+ }
1262+ }
1263+
1264+ public override bool ModifierItemsOptional {
1265+ get { return false; }
1266+ }
1267+
1268+ public override IEnumerable<Item> DynamicModifierItemsForItem(Item item) {
1269+ yield return new PriorityItem(TransmissionAPI.FilePriority.Low, "Low", "down");
1270+ yield return new PriorityItem(TransmissionAPI.FilePriority.Normal, "Normal", "forward");
1271+ yield return new PriorityItem(TransmissionAPI.FilePriority.High, "High", "up");
1272+ }
1273+
1274+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1275+ TransmissionAPI.FilePriority priority = (modItems.First() as PriorityItem).Value;
1276+
1277+ TransmissionAPI.FileOperation operation = new TransmissionAPI.FileOperation(null, priority);
1278+
1279+ // Group torrent entries by torrent.
1280+ var files_by_torrent = items
1281+ .Cast<ITorrentEntry>()
1282+ .GroupBy(
1283+ item => item.Torrent,
1284+ (torrent, entries) => new {
1285+ Torrent = torrent,
1286+ Files = entries.SelectMany(entry => entry.GetFiles())
1287+ }
1288+ );
1289+
1290+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1291+
1292+ // Expand entries for each torrent into set of torrent file entries.
1293+ // Perform action for each torrent separately.
1294+ foreach (var group in files_by_torrent) {
1295+ var operations = group.Files.ToDictionary(f => f.Index, f => operation);
1296+ api.SetTorrent(group.Torrent.HashString, null, null, null, null, null, operations);
1297+ }
1298+
1299+ yield break;
1300+ }
1301+ }
1302+}
1303
1304=== added file 'Transmission/src/TorrentItem.cs'
1305--- Transmission/src/TorrentItem.cs 1970-01-01 00:00:00 +0000
1306+++ Transmission/src/TorrentItem.cs 2010-07-26 16:47:47 +0000
1307@@ -0,0 +1,72 @@
1308+
1309+using System;
1310+using System.Collections.Generic;
1311+
1312+using Do.Universe;
1313+
1314+namespace Transmission {
1315+
1316+ public class TorrentItem: Item {
1317+
1318+ private string _name;
1319+ private string _comment;
1320+ private string _hash_string;
1321+ private long _size;
1322+ private TransmissionAPI.TorrentStatus _status;
1323+ private int _download_speed_limit, _upload_speed_limit;
1324+ private TorrentDirectoryItem _root;
1325+
1326+ public TorrentItem(TransmissionAPI.TorrentInfo info) {
1327+ _hash_string = info.HashString;
1328+ _name = info.Name;
1329+ _comment = info.Comment;
1330+ _status = info.Status;
1331+ _size = info.TotalSize;
1332+ _download_speed_limit = info.DownloadLimit;
1333+ _upload_speed_limit = info.UploadLimit;
1334+ _root = new TorrentDirectoryItem(this, null, info.DownloadDir);
1335+ }
1336+
1337+ public override string Name {
1338+ get { return _name; }
1339+ }
1340+
1341+ public override string Description {
1342+ get {
1343+ string status_text = "";
1344+ switch (_status) {
1345+ case TransmissionAPI.TorrentStatus.CheckWait: status_text = "Waiting for check"; break;
1346+ case TransmissionAPI.TorrentStatus.Check: status_text = "Checking"; break;
1347+ case TransmissionAPI.TorrentStatus.Download: status_text = "Downloading"; break;
1348+ case TransmissionAPI.TorrentStatus.Seed: status_text = "Seeding"; break;
1349+ case TransmissionAPI.TorrentStatus.Stopped: status_text = "Stopped"; break;
1350+ }
1351+
1352+ return string.Format("{0}, {1}", Utils.FormatSize(_size), status_text);
1353+ }
1354+ }
1355+
1356+ public override string Icon {
1357+ get { return "transmission"; }
1358+ }
1359+
1360+ public string HashString {
1361+ get { return _hash_string; }
1362+ }
1363+
1364+ public TorrentDirectoryItem Root {
1365+ get { return _root; }
1366+ }
1367+
1368+ public int DownloadSpeedLimit {
1369+ get { return _download_speed_limit; }
1370+ set { _download_speed_limit = value; }
1371+ }
1372+
1373+ public int UploadSpeedLimit {
1374+ get { return _upload_speed_limit; }
1375+ set { _upload_speed_limit = value; }
1376+ }
1377+ }
1378+
1379+}
1380
1381=== added file 'Transmission/src/TorrentItemSource.cs'
1382--- Transmission/src/TorrentItemSource.cs 1970-01-01 00:00:00 +0000
1383+++ Transmission/src/TorrentItemSource.cs 2010-07-26 16:47:47 +0000
1384@@ -0,0 +1,130 @@
1385+
1386+using System;
1387+using System.Collections.Generic;
1388+
1389+using Mono.Addins;
1390+
1391+using Do.Universe;
1392+using Do.Platform;
1393+using Do.Platform.Linux;
1394+
1395+namespace Transmission {
1396+
1397+ public class TorrentItemSource: ItemSource, IConfigurable {
1398+
1399+ private List<Item> _torrents = new List<Item>();
1400+
1401+ public TorrentItemSource() {
1402+ }
1403+
1404+ public override string Name {
1405+ get { return "Torrents"; }
1406+ }
1407+
1408+ public override string Description {
1409+ get { return "Transmission torrent client downloads"; }
1410+ }
1411+
1412+ public override string Icon {
1413+ get { return "transmission"; }
1414+ }
1415+
1416+ public override void UpdateItems () {
1417+ Log<TorrentItemSource>.Debug("Updating torrents list");
1418+
1419+ // Clear current torrents list.
1420+ _torrents.Clear();
1421+
1422+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1423+
1424+ foreach (TransmissionAPI.TorrentInfo t in api.GetAllTorrents()) {
1425+ Log<TorrentItemSource>.Debug("Torrent: {0}", t.Name);
1426+
1427+ TorrentItem torrent = new TorrentItem(t);
1428+
1429+ // Transmission returns files as flat list with full names, this map
1430+ // is used to organize files into hierarchy.
1431+ // It maps directory path to directory item.
1432+ Dictionary<string, TorrentDirectoryItem> dirs = new Dictionary<string, TorrentDirectoryItem>();
1433+ dirs.Add("", torrent.Root);
1434+
1435+ int index = 0; // File index within list.
1436+ foreach (TransmissionAPI.TorrentFileInfo f in t.files) {
1437+ // Split path and name.
1438+ int sep_pos = f.Name.LastIndexOf('/');
1439+
1440+ string name = f.Name.Substring(sep_pos+1);
1441+ string path = f.Name.Substring(0, sep_pos == -1 ? 0 : sep_pos);
1442+ Log<TorrentItemSource>.Debug("File {0} in dir {1}", name, path);
1443+ TorrentDirectoryItem dir = FindOrCreateDirectory(path, dirs);
1444+
1445+ dir.Files.Add(new TorrentFileItem(torrent, index, dir, name, f));
1446+
1447+ ++index;
1448+ }
1449+
1450+ _torrents.Add(torrent);
1451+ }
1452+ }
1453+
1454+ private TorrentDirectoryItem FindOrCreateDirectory(
1455+ string path,
1456+ Dictionary<string, TorrentDirectoryItem> dirs
1457+ ) {
1458+ TorrentDirectoryItem dir;
1459+ dirs.TryGetValue(path, out dir);
1460+
1461+ if (dir != null) {
1462+ // Found already added directory.
1463+ return dir;
1464+
1465+ } else {
1466+ // Directory doesn't exist, find or add parent one, then add this one.
1467+ int sep_pos = path.LastIndexOf('/');
1468+
1469+ string parent_path = path.Substring(0, sep_pos == -1 ? 0 : sep_pos);
1470+ TorrentDirectoryItem parent = FindOrCreateDirectory(parent_path, dirs);
1471+
1472+ string name = path.Substring(sep_pos+1);
1473+ dir = new TorrentDirectoryItem(parent.Torrent, parent, name);
1474+
1475+ parent.Files.Add(dir);
1476+ dirs.Add(path, dir);
1477+
1478+ return dir;
1479+ }
1480+ }
1481+
1482+ public override IEnumerable<Item> Items {
1483+ get { return _torrents; }
1484+ }
1485+
1486+ public override IEnumerable<Item> ChildrenOfItem(Item item) {
1487+ if (item is TorrentItem) {
1488+ foreach (Item entry in ((TorrentItem)item).Root.Files)
1489+ yield return entry;
1490+
1491+ } else if (item is TorrentDirectoryItem) {
1492+ foreach (Item entry in ((TorrentDirectoryItem)item).Files)
1493+ yield return entry;
1494+
1495+ } else {
1496+ yield break;
1497+
1498+ }
1499+ }
1500+
1501+ public override IEnumerable<Type> SupportedItemTypes {
1502+ get {
1503+ yield return typeof(TorrentItem);
1504+ yield return typeof(TorrentDirectoryItem);
1505+ yield return typeof(TorrentFileItem);
1506+ }
1507+ }
1508+
1509+ public Gtk.Bin GetConfiguration() {
1510+ return new TransmissionConfig();
1511+ }
1512+
1513+ }
1514+}
1515
1516=== added file 'Transmission/src/TorrentLimitDownloadSpeedAction.cs'
1517--- Transmission/src/TorrentLimitDownloadSpeedAction.cs 1970-01-01 00:00:00 +0000
1518+++ Transmission/src/TorrentLimitDownloadSpeedAction.cs 2010-07-26 16:47:47 +0000
1519@@ -0,0 +1,47 @@
1520+
1521+using System;
1522+using System.Linq;
1523+using System.Collections.Generic;
1524+using System.Text.RegularExpressions;
1525+
1526+using Mono.Addins;
1527+
1528+using Do.Platform;
1529+using Do.Universe;
1530+
1531+namespace Transmission {
1532+
1533+ public class TorrentLimitDownloadSpeedAction: TorrentAbstractLimitSpeedAction {
1534+
1535+ public override string Name {
1536+ get { return AddinManager.CurrentLocalizer.GetString("Limit download speed"); }
1537+ }
1538+
1539+ public override string Description {
1540+ get { return AddinManager.CurrentLocalizer.GetString("Set download speed limit"); }
1541+ }
1542+
1543+ public override string Icon {
1544+ get { return "top"; }
1545+ }
1546+
1547+ protected override PredefinedSpeed GetCurrentSpeedItem(TorrentItem torrent) {
1548+ int currentSpeed = torrent.DownloadSpeedLimit;
1549+ return new PredefinedSpeed(
1550+ currentSpeed,
1551+ string.Format("Saved: {0}", Utils.FormatSpeed(currentSpeed)),
1552+ "Use limit from torrent settings"
1553+ );
1554+ }
1555+
1556+ protected override void SetSpeedLimit(TransmissionAPI api, IEnumerable<TorrentItem> torrents, int speed) {
1557+ bool limit_speed = (speed != 0);
1558+ int? limit = (speed == 0 ? (int?)null : speed);
1559+ api.SetTorrents(torrents.Select(t => t.HashString), null, limit_speed, limit, null, null);
1560+
1561+ foreach (TorrentItem torrent in torrents)
1562+ torrent.DownloadSpeedLimit = speed;
1563+ }
1564+
1565+ }
1566+}
1567
1568=== added file 'Transmission/src/TorrentLimitUploadSpeedAction.cs'
1569--- Transmission/src/TorrentLimitUploadSpeedAction.cs 1970-01-01 00:00:00 +0000
1570+++ Transmission/src/TorrentLimitUploadSpeedAction.cs 2010-07-26 16:47:47 +0000
1571@@ -0,0 +1,47 @@
1572+
1573+using System;
1574+using System.Linq;
1575+using System.Collections.Generic;
1576+using System.Text.RegularExpressions;
1577+
1578+using Mono.Addins;
1579+
1580+using Do.Platform;
1581+using Do.Universe;
1582+
1583+namespace Transmission {
1584+
1585+ public class TorrentLimitUploadSpeedAction: TorrentAbstractLimitSpeedAction {
1586+
1587+ public override string Name {
1588+ get { return AddinManager.CurrentLocalizer.GetString ("Limit upload speed"); }
1589+ }
1590+
1591+ public override string Description {
1592+ get { return AddinManager.CurrentLocalizer.GetString ("Set upload speed limit"); }
1593+ }
1594+
1595+ public override string Icon {
1596+ get { return "top"; }
1597+ }
1598+
1599+ protected override PredefinedSpeed GetCurrentSpeedItem(TorrentItem torrent) {
1600+ int currentSpeed = torrent.UploadSpeedLimit;
1601+ return new PredefinedSpeed(
1602+ currentSpeed,
1603+ string.Format("Saved: {0}", Utils.FormatSpeed(currentSpeed)),
1604+ "Use limit from torrent settings"
1605+ );
1606+ }
1607+
1608+ protected override void SetSpeedLimit(TransmissionAPI api, IEnumerable<TorrentItem> torrents, int speed) {
1609+ bool limit_speed = (speed != 0);
1610+ int? limit = (speed == 0 ? (int?)null : speed);
1611+ api.SetTorrents(torrents.Select(t => t.HashString), null, null, null, limit_speed, limit);
1612+
1613+ foreach (TorrentItem torrent in torrents)
1614+ torrent.UploadSpeedLimit = speed;
1615+ }
1616+
1617+ }
1618+}
1619
1620=== added file 'Transmission/src/TorrentMarkForDownloadAction.cs'
1621--- Transmission/src/TorrentMarkForDownloadAction.cs 1970-01-01 00:00:00 +0000
1622+++ Transmission/src/TorrentMarkForDownloadAction.cs 2010-07-26 16:47:47 +0000
1623@@ -0,0 +1,62 @@
1624+
1625+using System;
1626+using System.Linq;
1627+using System.Collections.Generic;
1628+
1629+using Mono.Addins;
1630+
1631+using Do.Platform;
1632+using Do.Universe;
1633+
1634+namespace Transmission {
1635+
1636+ public class TorrentMarkForDownloadAction: Act {
1637+
1638+ public TorrentMarkForDownloadAction() {
1639+ }
1640+
1641+ public override string Name {
1642+ get { return AddinManager.CurrentLocalizer.GetString ("Mark for download"); }
1643+ }
1644+
1645+ public override string Description {
1646+ get { return AddinManager.CurrentLocalizer.GetString ("Mark file as needed to be downloaded"); }
1647+ }
1648+
1649+ public override string Icon {
1650+ get { return "add"; }
1651+ }
1652+
1653+ public override IEnumerable<Type> SupportedItemTypes {
1654+ get {
1655+ yield return typeof (ITorrentEntry);
1656+ }
1657+ }
1658+
1659+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1660+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1661+
1662+ // Operation is common for all files.
1663+ TransmissionAPI.FileOperation operation = new TransmissionAPI.FileOperation(true, null);
1664+
1665+ // Group selected items by owner torrent.
1666+ var files_by_torrent = items
1667+ .Cast<ITorrentEntry>()
1668+ .GroupBy(
1669+ item => item.Torrent,
1670+ (torrent, entries) => new {
1671+ Torrent = torrent,
1672+ Files = entries.SelectMany(entry => entry.GetFiles())
1673+ }
1674+ );
1675+
1676+ // Perform action for each torrent separately.
1677+ foreach (var group in files_by_torrent) {
1678+ var operations = group.Files.ToDictionary(f => f.Index, f => operation);
1679+ api.SetTorrent(group.Torrent.HashString, null, null, null, null, null, operations);
1680+ }
1681+
1682+ yield break;
1683+ }
1684+ }
1685+}
1686
1687=== added file 'Transmission/src/TorrentOperateAction.cs'
1688--- Transmission/src/TorrentOperateAction.cs 1970-01-01 00:00:00 +0000
1689+++ Transmission/src/TorrentOperateAction.cs 2010-07-26 16:47:47 +0000
1690@@ -0,0 +1,37 @@
1691+using System;
1692+using System.Linq;
1693+using System.Collections.Generic;
1694+
1695+using Mono.Addins;
1696+
1697+using Do.Universe;
1698+using Do.Platform;
1699+
1700+namespace Transmission {
1701+
1702+ public class TorrentOperateAction: Act {
1703+
1704+ public override string Name {
1705+ get { return AddinManager.CurrentLocalizer.GetString ("Operate on files"); }
1706+ }
1707+
1708+ public override string Description {
1709+ get { return AddinManager.CurrentLocalizer.GetString ("Operate on downloaded file"); }
1710+ }
1711+
1712+ public override string Icon {
1713+ get { return "file"; }
1714+ }
1715+
1716+ public override IEnumerable<Type> SupportedItemTypes {
1717+ get { yield return typeof (ITorrentEntry); }
1718+ }
1719+
1720+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1721+ foreach (Item item in items) {
1722+ ITorrentEntry entry = (ITorrentEntry)item;
1723+ yield return Services.UniverseFactory.NewFileItem(entry.Path) as Item;
1724+ }
1725+ }
1726+ }
1727+}
1728
1729=== added file 'Transmission/src/TorrentStartAction.cs'
1730--- Transmission/src/TorrentStartAction.cs 1970-01-01 00:00:00 +0000
1731+++ Transmission/src/TorrentStartAction.cs 2010-07-26 16:47:47 +0000
1732@@ -0,0 +1,42 @@
1733+
1734+using System;
1735+using System.Linq;
1736+using System.Collections.Generic;
1737+
1738+using Mono.Addins;
1739+
1740+using Do.Universe;
1741+
1742+namespace Transmission {
1743+
1744+ public class TorrentStartAction: Act {
1745+
1746+ public TorrentStartAction() {
1747+ }
1748+
1749+ public override string Name {
1750+ get { return AddinManager.CurrentLocalizer.GetString ("Start"); }
1751+ }
1752+
1753+ public override string Description {
1754+ get { return AddinManager.CurrentLocalizer.GetString ("Start downloading torrent"); }
1755+ }
1756+
1757+ public override string Icon {
1758+ get { return "gtk-media-play"; }
1759+ }
1760+
1761+ public override IEnumerable<Type> SupportedItemTypes {
1762+ get { yield return typeof (TorrentItem); }
1763+ }
1764+
1765+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1766+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1767+
1768+ var hashes = items.Cast<TorrentItem>().Select(t => t.HashString);
1769+ api.StartTorrents(hashes);
1770+
1771+ return null;
1772+ }
1773+ }
1774+}
1775
1776=== added file 'Transmission/src/TorrentStopAction.cs'
1777--- Transmission/src/TorrentStopAction.cs 1970-01-01 00:00:00 +0000
1778+++ Transmission/src/TorrentStopAction.cs 2010-07-26 16:47:47 +0000
1779@@ -0,0 +1,42 @@
1780+
1781+using System;
1782+using System.Linq;
1783+using System.Collections.Generic;
1784+
1785+using Mono.Addins;
1786+
1787+using Do.Universe;
1788+
1789+namespace Transmission {
1790+
1791+ public class TorrentStopAction: Act {
1792+
1793+ public TorrentStopAction() {
1794+ }
1795+
1796+ public override string Name {
1797+ get { return AddinManager.CurrentLocalizer.GetString ("Stop"); }
1798+ }
1799+
1800+ public override string Description {
1801+ get { return AddinManager.CurrentLocalizer.GetString ("Stop downloading torrent"); }
1802+ }
1803+
1804+ public override string Icon {
1805+ get { return "gtk-media-pause"; }
1806+ }
1807+
1808+ public override IEnumerable<Type> SupportedItemTypes {
1809+ get { yield return typeof (TorrentItem); }
1810+ }
1811+
1812+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1813+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1814+
1815+ var hashes = items.Cast<TorrentItem>().Select(t => t.HashString);
1816+ api.StopTorrents(hashes);
1817+
1818+ return null;
1819+ }
1820+ }
1821+}
1822
1823=== added file 'Transmission/src/TorrentUnmarkForDownloadAction.cs'
1824--- Transmission/src/TorrentUnmarkForDownloadAction.cs 1970-01-01 00:00:00 +0000
1825+++ Transmission/src/TorrentUnmarkForDownloadAction.cs 2010-07-26 16:47:47 +0000
1826@@ -0,0 +1,62 @@
1827+
1828+using System;
1829+using System.Linq;
1830+using System.Collections.Generic;
1831+
1832+using Mono.Addins;
1833+
1834+using Do.Platform;
1835+using Do.Universe;
1836+
1837+namespace Transmission {
1838+
1839+ public class TorrentUnmarkForDownloadAction: Act {
1840+
1841+ public TorrentUnmarkForDownloadAction() {
1842+ }
1843+
1844+ public override string Name {
1845+ get { return AddinManager.CurrentLocalizer.GetString ("Unmark for download"); }
1846+ }
1847+
1848+ public override string Description {
1849+ get { return AddinManager.CurrentLocalizer.GetString ("Unmark file as needed to be downloaded"); }
1850+ }
1851+
1852+ public override string Icon {
1853+ get { return "remove"; }
1854+ }
1855+
1856+ public override IEnumerable<Type> SupportedItemTypes {
1857+ get {
1858+ yield return typeof (ITorrentEntry);
1859+ }
1860+ }
1861+
1862+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1863+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1864+
1865+ // Operation is common for all files.
1866+ TransmissionAPI.FileOperation operation = new TransmissionAPI.FileOperation(false, null);
1867+
1868+ // Group selected items by owner torrent.
1869+ var files_by_torrent = items
1870+ .Cast<ITorrentEntry>()
1871+ .GroupBy(
1872+ item => item.Torrent,
1873+ (torrent, entries) => new {
1874+ Torrent = torrent,
1875+ Files = entries.SelectMany(entry => entry.GetFiles())
1876+ }
1877+ );
1878+
1879+ // Perform action for each torrent separately.
1880+ foreach (var group in files_by_torrent) {
1881+ var operations = group.Files.ToDictionary(f => f.Index, f => operation);
1882+ api.SetTorrent(group.Torrent.HashString, null, null, null, null, null, operations);
1883+ }
1884+
1885+ yield break;
1886+ }
1887+ }
1888+}
1889
1890=== added file 'Transmission/src/TorrentVerifyAction.cs'
1891--- Transmission/src/TorrentVerifyAction.cs 1970-01-01 00:00:00 +0000
1892+++ Transmission/src/TorrentVerifyAction.cs 2010-07-26 16:47:47 +0000
1893@@ -0,0 +1,42 @@
1894+
1895+using System;
1896+using System.Linq;
1897+using System.Collections.Generic;
1898+
1899+using Mono.Addins;
1900+
1901+using Do.Universe;
1902+
1903+namespace Transmission {
1904+
1905+ public class TorrentVerifyAction: Act {
1906+
1907+ public TorrentVerifyAction() {
1908+ }
1909+
1910+ public override string Name {
1911+ get { return AddinManager.CurrentLocalizer.GetString ("Verify"); }
1912+ }
1913+
1914+ public override string Description {
1915+ get { return AddinManager.CurrentLocalizer.GetString ("Verify torrent"); }
1916+ }
1917+
1918+ public override string Icon {
1919+ get { return "dialog-question"; }
1920+ }
1921+
1922+ public override IEnumerable<Type> SupportedItemTypes {
1923+ get { yield return typeof (TorrentItem); }
1924+ }
1925+
1926+ public override IEnumerable<Item> Perform(IEnumerable<Item> items, IEnumerable<Item> modItems) {
1927+ TransmissionAPI api = TransmissionPlugin.getTransmission();
1928+
1929+ var hashes = items.Cast<TorrentItem>().Select(t => t.HashString);
1930+ api.VerifyTorrents(hashes);
1931+
1932+ return null;
1933+ }
1934+ }
1935+}
1936
1937=== added file 'Transmission/src/TransmissionAPI.cs'
1938--- Transmission/src/TransmissionAPI.cs 1970-01-01 00:00:00 +0000
1939+++ Transmission/src/TransmissionAPI.cs 2010-07-26 16:47:47 +0000
1940@@ -0,0 +1,575 @@
1941+
1942+using System;
1943+using System.IO;
1944+using System.Collections;
1945+using System.Collections.Generic;
1946+using System.Net;
1947+using System.Text;
1948+using Jayrock.Json;
1949+
1950+namespace Transmission {
1951+
1952+ /// <summary>
1953+ /// Transmission API client.
1954+ /// Compatible with RPC version 5 to 10 (release version 1.60 to 2.10).
1955+ /// </summary>
1956+ public class TransmissionAPI {
1957+
1958+ /// <summary>
1959+ /// File loading priority.
1960+ /// </summary>
1961+ public enum FilePriority {
1962+ Low, Normal, High
1963+ };
1964+
1965+ /// <summary>
1966+ /// Operation on individual file from torrent.
1967+ /// </summary>
1968+ /// <remarks>
1969+ /// All fields are nullable, <c>null</c> means "don't change current value".
1970+ /// </remarks>
1971+ public struct FileOperation {
1972+ public FileOperation(bool? download, FilePriority? priority) {
1973+ this.download = download;
1974+ this.priority = priority;
1975+ }
1976+
1977+ /// <summary>Whether it is needed to download this file</summary>
1978+ public bool? download;
1979+
1980+ /// <summary>Priority relative to other files of the same torrent</summary>
1981+ public FilePriority? priority;
1982+ };
1983+
1984+ /// <summary>
1985+ /// Error communicating to Transmission.
1986+ /// </summary>
1987+ public class TransmissionAPIError: Exception {
1988+ public TransmissionAPIError(string message): base(message) {}
1989+ public TransmissionAPIError(string message, Exception reason): base(message, reason) {}
1990+ };
1991+
1992+ /// <summary>
1993+ /// Error returned by Transmission.
1994+ /// </summary>
1995+ public class TransmissionError: Exception {
1996+ public TransmissionError(string message): base(message) {
1997+ }
1998+ };
1999+
2000+ public const int DEFAULT_PORT = 9091;
2001+ public const string DEFAULT_PATH = "/transmission/rpc";
2002+ public const string SESSION_HEADER = "X-Transmission-Session-Id";
2003+
2004+ private string _url, _username, _password;
2005+ private string _session_id = "";
2006+
2007+ private delegate void ResultReader(JsonReader json);
2008+
2009+ /// <summary>Response handler which does nothing</summary>
2010+ /// <remarks>Prefer using <see cref="Call(string, IDictionary<string, object>)"/> instead</remarks>
2011+ private void NullHandler(JsonReader json) {}
2012+
2013+ /// <summary>
2014+ /// Create API client.
2015+ /// </summary>
2016+ /// <param name="url">Transmission API-RPC URL</param>
2017+ /// <param name="username">Username for authentication</param>
2018+ /// <param name="password">Password for authentication</param>
2019+ /// <remarks>Pass <c>null</c> for both <paramref="username"/> and <paramref="username"/> is
2020+ /// authentication isn't needed.</remarks>
2021+ public TransmissionAPI(string url, string username, string password) {
2022+ _url = url;
2023+ _username = username;
2024+ _password = password;
2025+ }
2026+
2027+ /// <summary>Compose request JSON string</summary>
2028+ protected string ComposeRequest(string method, IDictionary<string, object> arguments) {
2029+ StringWriter sw = new StringWriter();
2030+
2031+ using (JsonWriter json = new JsonTextWriter(sw)) {
2032+ json.WriteStartObject();
2033+
2034+ json.WriteMember("method");
2035+ json.WriteString(method);
2036+
2037+ json.WriteMember("arguments");
2038+ json.WriteStartObject();
2039+ foreach (KeyValuePair<string, object> pair in arguments) {
2040+ string name = pair.Key;
2041+ object value = pair.Value;
2042+
2043+ json.WriteMember(name);
2044+ Jayrock.Json.Conversion.JsonConvert.Export(value, json);
2045+ }
2046+ json.WriteEndObject();
2047+
2048+ json.WriteEndObject();
2049+ }
2050+
2051+ return sw.ToString();
2052+ }
2053+
2054+ /// <summary></summary>
2055+ /// <param name="payload">HTTP POST request content</param>
2056+ /// <returns>HTTP response content</returns>
2057+ /// <exception cref="System.Net.WebException"/>
2058+ protected string PerformRequest(byte[] payload) {
2059+ // Prepare request.
2060+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url);
2061+ request.Method = "POST";
2062+ request.ContentType = "application/x-www-form-urlencoded";
2063+ request.Headers[SESSION_HEADER] = _session_id;
2064+ request.ContentLength = payload.Length;
2065+
2066+ // Authenticate if credentials are given.
2067+ if (_username != null && _password != null) {
2068+ string auth = Convert.ToBase64String(Encoding.Default.GetBytes(_username + ":" + _password));
2069+ request.Headers["Authorization"] = "Basic " + auth;
2070+ }
2071+
2072+ // Perform request.
2073+ using (Stream stream = request.GetRequestStream()) {
2074+ stream.Write(payload, 0, payload.Length);
2075+ }
2076+
2077+ // Get response.
2078+ HttpWebResponse response = (HttpWebResponse)request.GetResponse();
2079+ return new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8).ReadToEnd();
2080+ }
2081+
2082+ /// <summary>
2083+ /// Call Transmission API method.
2084+ /// </summary>
2085+ /// <param name="method">API method name</param>
2086+ /// <param name="arguments">Arguments passed to API method</param>
2087+ /// <param name="handler">Function called with value returned by method</param>
2088+ /// <exception cref="TransmissionError" />
2089+ /// <exception cref="TransmissionAPIError" />
2090+ private void Call(string method, IDictionary<string, object> arguments, ResultReader handler) {
2091+ // Compose request and encode it to UTF-8.
2092+ string req = ComposeRequest(method, arguments);
2093+ byte[] reqb = System.Text.Encoding.UTF8.GetBytes(req);
2094+
2095+ try {
2096+
2097+ string resp = null;
2098+ try {
2099+ resp = PerformRequest(reqb);
2100+
2101+ } catch (System.Net.WebException err) {
2102+ HttpWebResponse response = (HttpWebResponse)err.Response;
2103+
2104+ // Transmission 1.53 and 1.6 introduced X-Transmission-Session-Id header
2105+ // in order to protect from CSRF attacks. If you make request without
2106+ // this header (or your session expire) you'll get 409 response with
2107+ // this header set. Just copy header to your request and try again.
2108+ if (
2109+ err.Status == WebExceptionStatus.ProtocolError &&
2110+ response.StatusCode == HttpStatusCode.Conflict
2111+ ) {
2112+ _session_id = response.Headers[SESSION_HEADER];
2113+ resp = PerformRequest(reqb);
2114+
2115+ } else {
2116+ throw;
2117+ }
2118+ }
2119+
2120+ JsonReader json_reader = new JsonTextReader(new StringReader(resp));
2121+
2122+ json_reader.ReadToken(JsonTokenClass.Object);
2123+ while (json_reader.TokenClass == JsonTokenClass.Member) {
2124+ switch (json_reader.ReadMember()) {
2125+ case "result":
2126+ string result = json_reader.ReadString();
2127+ if (result != "success")
2128+ throw new TransmissionError(result);
2129+ break;
2130+ case "tag":
2131+ json_reader.ReadNumber();
2132+ break;
2133+ case "arguments":
2134+ json_reader.ReadToken(JsonTokenClass.Object);
2135+ handler(json_reader);
2136+ json_reader.ReadToken(JsonTokenClass.EndObject);
2137+ break;
2138+ default:
2139+ json_reader.Skip();
2140+ break;
2141+ }
2142+ }
2143+ json_reader.ReadToken(JsonTokenClass.EndObject);
2144+ json_reader.ReadToken(JsonTokenClass.EOF);
2145+
2146+ } catch (System.Net.WebException err) {
2147+ throw new TransmissionAPIError("Cannot access Transmission RPC service", err);
2148+ }
2149+ }
2150+
2151+ /// <summary>Call API method and ignore return value</summary>
2152+ /// <remarks>This is equivalent to <c>Call(method, arguments, NullHandler)</c>.</remarks>
2153+ private void Call(string method, IDictionary<string, object> arguments) {
2154+ Call(method, arguments, NullHandler);
2155+ }
2156+
2157+ /// <summary>
2158+ /// Start torrents.
2159+ /// </summary>
2160+ /// <param name="torrent_hashes">Sequence of torrent's hashes</param>
2161+ /// <exception cref="TransmissionAPIError" />
2162+ /// <exception cref="TransmissionError" />
2163+ public void StartTorrents(IEnumerable<string> torrent_hashes) {
2164+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2165+ arguments.Add("ids", torrent_hashes);
2166+ Call("torrent-start", arguments);
2167+ }
2168+
2169+ /// <summary>
2170+ /// Start all torrents.
2171+ /// </summary>
2172+ /// <exception cref="TransmissionAPIError" />
2173+ /// <exception cref="TransmissionError" />
2174+ public void StartAllTorrents() {
2175+ Call("torrent-start", new Dictionary<string, object>());
2176+ }
2177+
2178+ /// <summary>
2179+ /// Stop torrents.
2180+ /// </summary>
2181+ /// <param name="torrent_hashes">Sequence of torrent's hashes</param>
2182+ /// <exception cref="TransmissionAPIError" />
2183+ /// <exception cref="TransmissionError" />
2184+ public void StopTorrents(IEnumerable<string> torrent_hashes) {
2185+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2186+ arguments.Add("ids", torrent_hashes);
2187+ Call("torrent-stop", arguments);
2188+ }
2189+
2190+ /// <summary>
2191+ /// Stop all torrents.
2192+ /// </summary>
2193+ /// <exception cref="TransmissionAPIError" />
2194+ /// <exception cref="TransmissionError" />
2195+ public void StopAllTorrents() {
2196+ Call("torrent-stop", new Dictionary<string, object>());
2197+ }
2198+
2199+ /// <summary>
2200+ /// Start torrents verification.
2201+ /// </summary>
2202+ /// <param name="torrent_hashes">Sequence of torrent's hashes to verify</param>
2203+ /// <exception cref="TransmissionAPIError" />
2204+ /// <exception cref="TransmissionError" />
2205+ public void VerifyTorrents(IEnumerable<string> torrent_hashes) {
2206+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2207+ arguments.Add("ids", torrent_hashes);
2208+ Call("torrent-verify", arguments);
2209+ }
2210+
2211+ /// <summary>
2212+ /// Start torrents verification for all torrents.
2213+ /// </summary>
2214+ /// <exception cref="TransmissionAPIError" />
2215+ /// <exception cref="TransmissionError" />
2216+ public void VerifyAllTorrents() {
2217+ Call("torrent-verify", new Dictionary<string, object>());
2218+ }
2219+
2220+ /// <summary>
2221+ /// Set torrents' properties.
2222+ ///
2223+ /// Not all torrent properties can be changed using this method, because some of them
2224+ /// are meaningless for torrent group, e.g. file priorities. Use <c>SetTorrent</c> method
2225+ /// to set such properties.
2226+ /// </summary>
2227+ /// <param name="torrent_hashes">Sequence of torrents hashed to modify</param>
2228+ /// <param name="peer_limit">Maximum number of used peers, if it is <c>null</c> then value won't be changed.</param>
2229+ /// <param name="limit_download">
2230+ /// Downloading speed limit switch, if it is <c>true</c>, downloading speed will be limited,
2231+ /// if it is <c>false</c>, downloading speed isn't limited, if it is <c>null</c>, limit switch won't be changed.
2232+ /// A <see cref="System.Nullable"/>
2233+ /// </param>
2234+ /// <param name="download_speed_limit">
2235+ /// A <see cref="System.Nullable"/>
2236+ /// </param>
2237+ /// <param name="limit_upload">
2238+ /// A <see cref="System.Nullable"/>
2239+ /// </param>
2240+ /// <param name="upload_speed_limit">
2241+ /// A <see cref="System.Nullable"/>
2242+ /// </param>
2243+ public void SetTorrents(IEnumerable<string> torrent_hashes, int? peer_limit, bool? limit_download, int? download_speed_limit, bool? limit_upload, int? upload_speed_limit) {
2244+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2245+
2246+ arguments.Add("ids", torrent_hashes);
2247+
2248+ if (peer_limit != null)
2249+ arguments.Add("peer-limit", peer_limit);
2250+
2251+ if (limit_download.HasValue) {
2252+ if (limit_download.Value) {
2253+ arguments.Add("downloadLimited", true);
2254+ if (download_speed_limit.HasValue)
2255+ arguments.Add("downloadLimit", download_speed_limit.Value);
2256+ } else {
2257+ arguments.Add("downloadLimited", false);
2258+ }
2259+ }
2260+
2261+ if (limit_upload.HasValue) {
2262+ if (limit_upload.Value) {
2263+ arguments.Add("uploadLimited", true);
2264+ if (upload_speed_limit.HasValue)
2265+ arguments.Add("uploadLimit", upload_speed_limit.Value);
2266+ } else {
2267+ arguments.Add("uploadLimited", false);
2268+ }
2269+ }
2270+
2271+ Call("torrent-set", arguments);
2272+ }
2273+
2274+ public void SetTorrent(string torrent_hash, int? peer_limit, bool? limit_download, int? download_speed_limit, bool? limit_upload, int? upload_speed_limit, IDictionary<int, FileOperation> files) {
2275+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2276+
2277+ arguments.Add("ids", new string[] { torrent_hash });
2278+
2279+ if (peer_limit != null)
2280+ arguments.Add("peer-limit", peer_limit);
2281+
2282+ if (limit_download.HasValue) {
2283+ if (limit_download.Value) {
2284+ arguments.Add("downloadLimited", true);
2285+ if (download_speed_limit.HasValue)
2286+ arguments.Add("downloadLimit", download_speed_limit.Value);
2287+ } else {
2288+ arguments.Add("downloadLimited", false);
2289+ }
2290+ }
2291+
2292+ if (limit_upload.HasValue) {
2293+ if (limit_upload.Value) {
2294+ arguments.Add("uploadLimited", true);
2295+ if (upload_speed_limit.HasValue)
2296+ arguments.Add("uploadLimit", upload_speed_limit.Value);
2297+ } else {
2298+ arguments.Add("uploadLimited", false);
2299+ }
2300+ }
2301+
2302+ List<int> wanted_files = new List<int>();
2303+ List<int> unwanted_files = new List<int>();
2304+ List<int> low_priority_files = new List<int>();
2305+ List<int> normal_priority_files = new List<int>();
2306+ List<int> high_priority_files = new List<int>();
2307+ foreach (KeyValuePair<int, FileOperation> op in files) {
2308+ int index = op.Key;
2309+ FileOperation file = op.Value;
2310+
2311+ if (file.download.HasValue) {
2312+ if (file.download.Value) wanted_files.Add(index);
2313+ else unwanted_files.Add(index);
2314+ }
2315+
2316+ if (file.priority.HasValue) {
2317+ switch (file.priority.Value) {
2318+ case FilePriority.Low: low_priority_files.Add(index); break;
2319+ case FilePriority.Normal: normal_priority_files.Add(index); break;
2320+ case FilePriority.High: high_priority_files.Add(index); break;
2321+ }
2322+ }
2323+ }
2324+ if (wanted_files.Count > 0) arguments.Add("files-wanted", wanted_files);
2325+ if (unwanted_files.Count > 0) arguments.Add("files-unwanted", unwanted_files);
2326+ if (low_priority_files.Count > 0) arguments.Add("priority-low", low_priority_files);
2327+ if (normal_priority_files.Count > 0) arguments.Add("priority-normal", normal_priority_files);
2328+ if (high_priority_files.Count > 0) arguments.Add("priority-high", high_priority_files);
2329+
2330+ Call("torrent-set", arguments);
2331+ }
2332+
2333+ /// <summary>
2334+ /// Torrent status.
2335+ /// </summary>
2336+ public enum TorrentStatus {
2337+ CheckWait = 1, Check = 2, Download = 4, Seed = 8, Stopped = 16
2338+ };
2339+
2340+ public class TorrentInfo {
2341+ public int Id; // Torrent's unique ID within Transmission.
2342+ public string Comment;
2343+ public string HashString;
2344+ public string Name;
2345+ public string DownloadDir;
2346+ public IList<TorrentFileInfo> files;
2347+ public TorrentStatus Status;
2348+ public long TotalSize;
2349+
2350+ public int DownloadLimit;
2351+ public bool DownloadLimited;
2352+ public int UploadLimit;
2353+ public bool UploadLimited;
2354+ };
2355+
2356+ public class TorrentFileInfo {
2357+ public string Name;
2358+ public long Length;
2359+ public long BytesCompleted;
2360+ public bool Wanted;
2361+ public FilePriority Priority;
2362+ };
2363+
2364+ /// <summary>Get information about all torrents.</summary>
2365+ /// <remarks>This is equivalent to <c>GetTorrents(null)</c>.</remarks>
2366+ public IEnumerable<TorrentInfo> GetAllTorrents() {
2367+ return GetTorrents(null);
2368+ }
2369+
2370+ public IEnumerable<TorrentInfo> GetTorrents(IEnumerable<string> torrent_hashes) {
2371+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2372+ if (torrent_hashes != null) arguments.Add("ids", torrent_hashes);
2373+ arguments.Add("fields", new string[] {"comment", "downloadDir", "files", "hashString", "id", "name", "priorities", "status", "totalSize", "wanted", "downloadLimited", "downloadLimit", "uploadLimited", "uploadLimit"});
2374+
2375+ List<TorrentInfo> torrents = new List<TorrentInfo>();
2376+
2377+ Jayrock.Json.Conversion.ImportContext jsonctx = new Jayrock.Json.Conversion.ImportContext();
2378+ jsonctx.Register(new ListImporter<int>());
2379+ jsonctx.Register(new ListImporter<TorrentFileInfo>());
2380+
2381+ Call("torrent-get", arguments, delegate(JsonReader json) {
2382+ while (json.TokenClass == JsonTokenClass.Member) {
2383+ switch (json.ReadMember()) {
2384+ case "torrents":
2385+ json.ReadToken(JsonTokenClass.Array);
2386+ while (json.TokenClass != JsonTokenClass.EndArray) {
2387+
2388+ json.ReadToken(JsonTokenClass.Object);
2389+
2390+ TorrentInfo torrent = new TorrentInfo();
2391+ IList<TorrentFileInfo> files = null;
2392+ IList<int> wanted = null;
2393+ IList<int> priorities = null;
2394+
2395+ while (json.TokenClass == JsonTokenClass.Member) {
2396+ switch (json.ReadMember()) {
2397+ case "comment": torrent.Comment = json.ReadString(); break;
2398+ case "hashString": torrent.HashString = json.ReadString(); break;
2399+ case "name": torrent.Name = json.ReadString(); break;
2400+ case "id": torrent.Id = json.ReadNumber().ToInt32(); break;
2401+ case "downloadDir": torrent.DownloadDir = json.ReadString(); break;
2402+ case "status": torrent.Status = (TorrentStatus)json.ReadNumber().ToInt32(); break;
2403+ case "totalSize": torrent.TotalSize = json.ReadNumber().ToInt64(); break;
2404+ case "wanted": wanted = (IList<int>)jsonctx.Import(typeof(List<int>), json); break;
2405+ case "priorities": priorities = (IList<int>)jsonctx.Import(typeof(List<int>), json); break;
2406+ case "files": files = jsonctx.Import(typeof(List<TorrentFileInfo>), json) as IList<TorrentFileInfo>; break;
2407+ case "downloadLimited": torrent.DownloadLimited = json.ReadBoolean(); break;
2408+ case "downloadLimit": torrent.DownloadLimit = json.ReadNumber().ToInt32(); break;
2409+ case "uploadLimited": torrent.UploadLimited = json.ReadBoolean(); break;
2410+ case "uploadLimit": torrent.UploadLimit = json.ReadNumber().ToInt32(); break;
2411+ }
2412+ }
2413+
2414+ for (int i = 0; i < files.Count; ++i) {
2415+ files[i].Wanted = wanted[i] == 1;
2416+
2417+ int prio = priorities[i];
2418+ if (prio < -1 || prio > 1)
2419+ throw new TransmissionAPIError(string.Format("Invalid priority value: {0}", prio));
2420+ files[i].Priority = (FilePriority)(prio+1);
2421+ }
2422+ torrent.files = files;
2423+ torrents.Add(torrent);
2424+
2425+ json.ReadToken(JsonTokenClass.EndObject);
2426+ }
2427+ json.ReadToken(JsonTokenClass.EndArray);
2428+ break;
2429+ default:
2430+ json.Skip();
2431+ break;
2432+ }
2433+ }
2434+ });
2435+
2436+ return torrents;
2437+ }
2438+
2439+ // Transmission RPC allows to use .torrent file content instead of it's filename, but
2440+ // this isn't supported.
2441+ public void AddTorrent(string filename, string download_to, bool paused, int? peer_limit) {
2442+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2443+ arguments.Add("filename", filename);
2444+ arguments.Add("download-dir", download_to);
2445+ arguments.Add("paused", paused);
2446+ if (peer_limit.HasValue) arguments.Add("peer-limit", peer_limit.Value);
2447+ Call("torrent-add", arguments);
2448+ }
2449+
2450+ /// <summary>
2451+ /// Remove torrents.
2452+ /// </summary>
2453+ /// <param name="hashes">Sequence of torrent hashes to remove.</param>
2454+ /// <param name="delete_files">Whether downloaded files should be deleted or not.</param>
2455+ public void RemoveTorrent(IEnumerable<string> hashes, bool delete_files) {
2456+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2457+ arguments.Add("ids", hashes);
2458+ arguments.Add("delete-load-data", delete_files);
2459+ Call("torrent-remove", arguments);
2460+ }
2461+
2462+ /// <summary>
2463+ /// Set session parameters.
2464+ /// </summary>
2465+ /// <param name="download_dir">
2466+ /// Path to directory to download torrent contents to.
2467+ /// Pass <c>null</c> to keep old value.
2468+ /// </param>
2469+ /// <param name="peer_limit">
2470+ /// Global limit on number of connected peers. Pass <c>null</c> to keep old value.
2471+ /// </param>
2472+ /// <param name="limit_download">
2473+ /// Global limit on number of connected peers. Pass <c>null</c> to keep old value.
2474+ /// </param>
2475+ public void SetSession(
2476+ string download_dir, int? peer_limit,
2477+ bool? limit_download, int? download_speed_limit, bool? limit_upload, int? upload_speed_limit
2478+ ) {
2479+ Dictionary<string, object> arguments = new Dictionary<string, object>();
2480+
2481+ if (download_dir != null)
2482+ arguments.Add("download-dir", download_dir);
2483+
2484+ if (peer_limit.HasValue)
2485+ arguments.Add("peer-limit", peer_limit.Value);
2486+
2487+ if (limit_download.HasValue) {
2488+ if (limit_download.Value) {
2489+ arguments.Add("downloadLimited", true);
2490+ if (download_speed_limit.HasValue)
2491+ arguments.Add("downloadLimit", download_speed_limit.Value);
2492+ } else {
2493+ arguments.Add("downloadLimited", false);
2494+ }
2495+ }
2496+
2497+ if (limit_upload.HasValue) {
2498+ if (limit_upload.Value) {
2499+ arguments.Add("uploadLimited", true);
2500+ if (upload_speed_limit.HasValue)
2501+ arguments.Add("uploadLimit", upload_speed_limit.Value);
2502+ } else {
2503+ arguments.Add("uploadLimited", false);
2504+ }
2505+ }
2506+
2507+ Call("session-set", arguments);
2508+ }
2509+
2510+ public void GetSession() {
2511+ Call("session-get", new Dictionary<string, object>());
2512+ }
2513+
2514+ }
2515+}
2516
2517=== added file 'Transmission/src/TransmissionPlugin.cs'
2518--- Transmission/src/TransmissionPlugin.cs 1970-01-01 00:00:00 +0000
2519+++ Transmission/src/TransmissionPlugin.cs 2010-07-26 16:47:47 +0000
2520@@ -0,0 +1,50 @@
2521+using System;
2522+using System.Collections.Generic;
2523+
2524+using Do.Platform;
2525+
2526+namespace Transmission {
2527+
2528+ public class ConnectionParameters {
2529+ public ConnectionParameters(string url, string username, string password) {
2530+ this.url = url;
2531+ this.username = username;
2532+ this.password = password;
2533+ }
2534+
2535+ public string url;
2536+ public string username;
2537+ public string password;
2538+ };
2539+
2540+ public class TransmissionPlugin {
2541+ private static TransmissionAPI transmission;
2542+
2543+ public static TransmissionAPI getTransmission() {
2544+ if (transmission == null) {
2545+ ConnectionParameters p = getTransmissionConnectionParameters();
2546+ Log<TransmissionPlugin>.Info("Using Transmission on {0}", p.url);
2547+ Log<TransmissionPlugin>.Debug("Using name, password: {0}:{1}", p.username, p.password);
2548+ transmission = new TransmissionAPI(p.url, p.username, p.password);
2549+ }
2550+ return transmission;
2551+ }
2552+
2553+ public static void ResetConnection() {
2554+ transmission = null;
2555+ }
2556+
2557+ public static ConnectionParameters getTransmissionConnectionParameters() {
2558+ string host = TransmissionConfig.Address;
2559+ int port = TransmissionConfig.Port;
2560+ string username = TransmissionConfig.UserName;
2561+ string password = TransmissionConfig.Password;
2562+
2563+ string url = string.Format("http://{0}:{1}/transmission/rpc", host, port);
2564+ return new ConnectionParameters(url, username, password);
2565+ }
2566+
2567+ };
2568+
2569+}
2570+
2571
2572=== added file 'Transmission/src/Utils.cs'
2573--- Transmission/src/Utils.cs 1970-01-01 00:00:00 +0000
2574+++ Transmission/src/Utils.cs 2010-07-26 16:47:47 +0000
2575@@ -0,0 +1,111 @@
2576+
2577+using System;
2578+using System.Linq;
2579+using System.Collections.Generic;
2580+using System.Text.RegularExpressions;
2581+
2582+using Do.Platform;
2583+using Do.Universe;
2584+
2585+namespace Transmission {
2586+
2587+ class Utils {
2588+
2589+ public static int ParseSpeed(string speed) {
2590+ Regex regex = new Regex(
2591+ @"^(\d+)\s*(b|[km]i?b?)$",
2592+ RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace
2593+ );
2594+ Match match = regex.Match(speed);
2595+
2596+ if (match.Success) {
2597+ int number = int.Parse(match.Groups[1].Value);
2598+ string unit = match.Groups[2].Value.ToLower();
2599+ int scale = 1;
2600+
2601+ if (unit == "" || unit[0] == 'k') scale = 1;
2602+ else if (unit[0] == 'm') scale = 1024;
2603+
2604+ return number * scale;
2605+
2606+ } else {
2607+ throw new ArgumentException("Invalid speed string");
2608+ }
2609+ }
2610+
2611+ public static string FormatAmount(float amount, string baseFormat, float[] scales, string[] formats) {
2612+ if (scales.Length != formats.Length)
2613+ throw new ArgumentException("'scales' and 'formats' arguments must have equal length");
2614+
2615+ // The typical scales count is three to five, so don't use binary search,
2616+ // but just plain reverse loop.
2617+ for (int i = scales.Length-1; i >= 0; --i) {
2618+ if (amount >= scales[i])
2619+ return string.Format(formats[i], amount / scales[i]);
2620+ }
2621+
2622+ return string.Format(baseFormat, amount);
2623+ }
2624+
2625+ // Format speed in KiB/sec into human-readable representation.
2626+ public static string FormatSpeed(int speed_kbytes_sec) {
2627+ return FormatAmount(speed_kbytes_sec, "{0} KiB/sec",
2628+ new float[] { 1024, 1024*1024},
2629+ new string[] {"{0:#.#} MiB/sec", "{0:#.#} GiB/sec"}
2630+ );
2631+ }
2632+
2633+ // Format size in bytes into human-readable representation.
2634+ public static string FormatSize(long size_bytes) {
2635+ return FormatAmount(size_bytes, "{0} B",
2636+ new float[] { 1024, 1024*1024, 1024*1024*1024},
2637+ new string[] {"{0:#.#} KiB", "{0:#.#} MiB", "{0:#.##} GiB"}
2638+ );
2639+ }
2640+
2641+ public readonly static IEnumerable<PredefinedSpeed> PredefinedSpeedItems = new List<PredefinedSpeed>() {
2642+ new PredefinedSpeed( 10, "10 KiB/sec", ""),
2643+ new PredefinedSpeed( 20, "20 KiB/sec", ""),
2644+ new PredefinedSpeed( 50, "50 KiB/sec", ""),
2645+ new PredefinedSpeed( 100, "100 KiB/sec", ""),
2646+ new PredefinedSpeed( 200, "200 KiB/sec", ""),
2647+ new PredefinedSpeed( 500, "500 KiB/sec", ""),
2648+ new PredefinedSpeed( 1 * 1024, "1 MiB/sec", ""),
2649+ new PredefinedSpeed( 2 * 1024, "2 MiB/sec", ""),
2650+ new PredefinedSpeed( 5 * 1024, "5 MiB/sec", ""),
2651+ new PredefinedSpeed( 10 * 1024, "10 MiB/sec", ""),
2652+ new PredefinedSpeed( 20 * 1024, "20 MiB/sec", ""),
2653+ new PredefinedSpeed( 50 * 1024, "50 MiB/sec", ""),
2654+ new PredefinedSpeed(100 * 1024, "100 MiB/sec", ""),
2655+ };
2656+
2657+ }
2658+
2659+ public class PredefinedSpeed: Item {
2660+ private string _name, _desc;
2661+ private int _value;
2662+
2663+ public PredefinedSpeed(int value, string name, string desc) {
2664+ _value = value;
2665+ _name = name;
2666+ _desc = desc;
2667+ }
2668+
2669+ public override string Name {
2670+ get { return _name; }
2671+ }
2672+
2673+ public override string Description {
2674+ get { return _desc; }
2675+ }
2676+
2677+ public override string Icon {
2678+ get { return "top"; }
2679+ }
2680+
2681+ public int Value {
2682+ get { return _value; }
2683+ }
2684+ }
2685+
2686+}
2687
2688=== modified file 'configure.ac'
2689--- configure.ac 2010-03-08 02:43:56 +0000
2690+++ configure.ac 2010-07-26 16:47:47 +0000
2691@@ -383,6 +383,8 @@
2692 Tracker/Resources/TrackerSearch.addin.xml
2693 Translate/Makefile
2694 Translate/Resources/Translate.addin.xml
2695+Transmission/Makefile
2696+Transmission/Resources/Transmission.addin.xml
2697 Tomboy/Makefile
2698 Tomboy/Resources/Tomboy.addin.xml
2699 Vinagre/Makefile

Subscribers

People subscribed via source and target branches