comparison ARClient/Form1.cs @ 0:90ea68d4f92f

First release
author Ivo Smits <Ivo@UCIS.nl>
date Sat, 08 Nov 2014 22:43:51 +0100
parents
children 27ccad26a830
comparison
equal deleted inserted replaced
-1:000000000000 0:90ea68d4f92f
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.IO;
5 using System.Text;
6 using System.Windows.Forms;
7 using UCIS.NaCl.v2;
8 using UCIS.Util;
9
10 namespace ARClient {
11 partial class Form1 : Form {
12 public Boolean DatabaseSaved { get; set; }
13 public String Database { get; private set; }
14 public ed25519keypair SecretKey { get; set; }
15 public MARCKey PublicKey { get; set; }
16 public Dictionary<MARCLabel, MARCUpdate> Resources { get; private set; }
17 public List<String> Peers { get; private set; }
18 public List<MARCKey> BlockedKeys { get; private set; }
19 public ResourceTypeFilter FilterFlags { get; set; }
20
21 public enum ResourceTypeFilter : uint {
22 AnonetIPv4 = 1,
23 AnonetIPv6 = 2,
24 AnonetDomain = 4,
25 ASNumber= 8,
26 OtherIPv4 = 16,
27 OtherIPv6 = 32,
28 OtherDomain = 64,
29 Other = 128,
30 Invalid = 256,
31 Key = 512,
32
33 None = 0,
34 All = 0xffffffff,
35 }
36
37 public Form1() {
38 InitializeComponent();
39 }
40
41 private void Form1_Load(object sender, EventArgs e) {
42 DatabaseSaved = true;
43 String dbpath = Path.Combine(Environment.CurrentDirectory, "marc.mdb");
44 if (!File.Exists(dbpath) || !LoadDatabase(dbpath)) {
45 MessageBox.Show("The standard database could not be loaded. The system will now generate a new key pair. If you already have a key pair and want to use it, make sure to import the key file or open the existing database.", "MARC - New database", MessageBoxButtons.OK, MessageBoxIcon.Information);
46 CreateDatabase();
47 if (!File.Exists(dbpath)) Database = dbpath;
48 }
49 cmbResourceFilter.SelectedIndex = 0;
50 }
51
52 public void UpdatePeersList() {
53 synchronizeResourcesToolStripMenuItem.DropDownItems.Clear();
54 ToolStripItem item = synchronizeResourcesToolStripMenuItem.DropDownItems.Add("All peers");
55 item.Tag = null;
56 item.Click += SynchronizeServerToolStripMenuItem_Click;
57 foreach (String peer in Peers) {
58 item = synchronizeResourcesToolStripMenuItem.DropDownItems.Add(peer);
59 item.Tag = peer;
60 item.Click += SynchronizeServerToolStripMenuItem_Click;
61 }
62 }
63
64 internal Boolean IsResourceFiltered(MARCUpdate update) {
65 if (BlockedKeys.Contains(update.Key)) return true;
66 Byte[] label = update.Label.Bytes;
67 if (label == null || label.Length < 1) return 0 != (FilterFlags & ResourceTypeFilter.Invalid);
68 switch (label[0]) {
69 case 0:
70 if (label.Length != 33 || !ArrayUtil.Equal(ArrayUtil.Slice(label, 1), update.Key.Bytes)) return 0 == (FilterFlags & ResourceTypeFilter.Invalid);
71 return 0 == (FilterFlags & ResourceTypeFilter.Key);
72 case 1:
73 if (label.Length != 6) return 0 == (FilterFlags & ResourceTypeFilter.Invalid);
74 if (label[5] > 32) return 0 == (FilterFlags & ResourceTypeFilter.Invalid);
75 if (label[1] == 1) return 0 == (FilterFlags & ResourceTypeFilter.AnonetIPv4);
76 return 0 == (FilterFlags & ResourceTypeFilter.OtherIPv4);
77 case 2:
78 if (label.Length != 18) return 0 == (FilterFlags & ResourceTypeFilter.Invalid);
79 if (label[17] > 128) return 0 == (FilterFlags & ResourceTypeFilter.Invalid);
80 if (label[1] == 0xfc || label[1] == 0xfd) return 0 == (FilterFlags & ResourceTypeFilter.AnonetIPv6);
81 return 0 == (FilterFlags & ResourceTypeFilter.OtherIPv6);
82 case 3:
83 if (label.Length != 5) return 0 == (FilterFlags & ResourceTypeFilter.Invalid);
84 return 0 == (FilterFlags & ResourceTypeFilter.ASNumber);
85 case 4:
86 String dom = Encoding.UTF8.GetString(label, 1, label.Length - 1);
87 if (dom.EndsWith(".ano")) return 0 == (FilterFlags & ResourceTypeFilter.AnonetDomain);
88 return 0 == (FilterFlags & ResourceTypeFilter.OtherDomain);
89 default:
90 return 0 == (FilterFlags & ResourceTypeFilter.Other);
91 }
92 }
93
94 public void GenerateKeyPair() {
95 if (DialogResult.Yes != MessageBox.Show(this, "Generating a new key pair will erase your old key pair from the local database. If you lose your key you will no longer be able to update your resource claims. Please make sure that you either have a backup of your key, or have no claims! Do you want to continue?", "MARC - Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation)) {
96 return;
97 }
98 if (DialogResult.Yes != MessageBox.Show(this, "Are you really sure you want to overwrite your key? There is no way back! Did you make a backup?", "MARC - Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation)) {
99 return;
100 }
101 SecretKey = new ed25519keypair();
102 PublicKey = new MARCKey(SecretKey.PublicKey);
103 DatabaseSaved = false;
104 }
105
106 #region "Database UI stuff"
107 private Boolean WarnDatabaseSaved() {
108 if (DatabaseSaved) return true;
109 return DialogResult.Yes == MessageBox.Show(this, "The current database is not saved. You may lose data if you continue. Losing your key pair will render your unable to update your resources. Are you sure you want to continue?", "MARC - Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
110 }
111 private Boolean SaveDatabase() {
112 if (Database == null) {
113 return SaveDatabaseAs();
114 } else {
115 return SaveDatabase(Database);
116 }
117 }
118 private Boolean SaveDatabaseAs() {
119 SaveFileDialog dialog = new SaveFileDialog();
120 dialog.OverwritePrompt = true;
121 dialog.Title = "MARC - Save database file";
122 SetupFileDialog(dialog);
123 if (dialog.ShowDialog(this) != DialogResult.OK) return false;
124 return SaveDatabase(dialog.FileName);
125 }
126 private String SelectDatabaseOpen(String title) {
127 OpenFileDialog dialog = new OpenFileDialog();
128 dialog.Multiselect = false;
129 dialog.ShowReadOnly = false;
130 dialog.CheckFileExists = true;
131 dialog.Title = "MARC - " + title;
132 SetupFileDialog(dialog);
133 if (dialog.ShowDialog(this) != DialogResult.OK) return null;
134 return dialog.FileName;
135 }
136 private void SetupFileDialog(FileDialog dialog) {
137 dialog.AddExtension = true;
138 dialog.CheckPathExists = true;
139 dialog.DefaultExt = "mdb";
140 dialog.DereferenceLinks = true;
141 dialog.FileName = Database;
142 dialog.Filter = "MARC Database files (*.mdb)|*.mdb|All files (*.*)|*.*";
143 dialog.InitialDirectory = Database == null ? Environment.CurrentDirectory : Path.GetDirectoryName(Database);
144 dialog.SupportMultiDottedExtensions = true;
145 dialog.ValidateNames = true;
146 }
147 private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
148 if (DatabaseSaved) return;
149 switch (MessageBox.Show(this, "The current database has not been saved. Losing your key pair may render you unable to update your resources! Do you want to save the database?", "MARC - Warning", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning)) {
150 case DialogResult.Yes:
151 if (!SaveDatabase()) e.Cancel = true;
152 break;
153 case DialogResult.No:
154 break;
155 case DialogResult.Cancel:
156 e.Cancel = true;
157 break;
158 }
159 }
160 #endregion
161
162 #region "Database file"
163 private Boolean LoadDatabase(String fn) {
164 if (!WarnDatabaseSaved()) return false;
165 try {
166 lstResources.BeginUpdate();
167 lstResources.Sorted = false;
168 using (FileStream fs = File.OpenRead(fn)) {
169 BinaryReader br = new BinaryReader(fs, Encoding.UTF8);
170 if (br.ReadString() != "MARC") throw new Exception("This file is not a MARC database");
171 Byte version = br.ReadByte();
172 Resources = new Dictionary<MARCLabel, MARCUpdate>();
173 Peers = new List<string>();
174 BlockedKeys = new List<MARCKey>();
175 FilterFlags = ResourceTypeFilter.All;
176 lstResources.Items.Clear();
177 if (version == 2) {
178 SecretKey = new ed25519keypair(br.ReadBytes(32));
179 PublicKey = new MARCKey(SecretKey.PublicKey);
180
181 Int32 c = br.ReadInt32();
182 for (int i = 0; i < c; i++) {
183 Int32 len = br.ReadInt32();
184 if (len == 0) continue;
185 ImportUpdate(br.ReadBytes(len), true);
186 }
187
188 c = br.ReadInt32();
189 for (int i = 0; i < c; i++) Peers.Add(br.ReadString());
190 c = br.ReadInt32();
191 for (int i = 0; i < c; i++) BlockedKeys.Add(new MARCKey(br.ReadBytes(32)));
192
193 FilterFlags = (ResourceTypeFilter)br.ReadInt32();
194 } else if (version == 3) {
195 UInt32 len = Functions.FromBigEndian((UInt32)br.ReadInt32());
196 {
197 Byte[] metabytes = br.ReadBytes((int)len);
198 IDictionary metadata = MARCUpdate.DecodeValue(metabytes) as IDictionary;
199 if (metadata != null) {
200 if (metadata["keys"] != null)
201 foreach (IDictionary metakey in (IList)metadata["keys"]) {
202 if (!metakey.Contains("key")) continue;
203 SecretKey = new ed25519keypair(((BinaryString)metakey["key"]).Bytes);
204 PublicKey = new MARCKey(SecretKey.PublicKey);
205 break;
206 }
207 if (metadata["peers"] != null)
208 foreach (IDictionary metapeer in (IList)metadata["peers"])
209 Peers.Add(metapeer["address"].ToString());
210 if (metadata["blockedkeys"] != null)
211 foreach (BinaryString metablockedkey in (IList)metadata["blockedkeys"])
212 BlockedKeys.Add(new MARCKey(metablockedkey.Bytes));
213 if (metadata["filterflags"] != null)
214 FilterFlags = (ResourceTypeFilter)Functions.DecodeInt32BigEndian(((BinaryString)metadata["filterflags"]).Bytes, 0);
215 }
216 }
217 while (true) {
218 Byte[] lenbytes = br.ReadBytes(4);
219 if (lenbytes.Length == 0) break;
220 if (lenbytes.Length != 4) throw new Exception("Database truncated");
221 len = Functions.DecodeInt32BigEndian(lenbytes, 0);
222 ImportUpdate(br.ReadBytes((int)len), true);
223 }
224 } else {
225 throw new Exception("Unsupported database version");
226 }
227 br.Close();
228 Database = fn;
229 DatabaseSaved = true;
230 UpdatePeersList();
231 return true;
232 }
233 } catch (Exception ex) {
234 Console.Error.WriteLine(ex.ToString());
235 MessageBox.Show(this, "Failed to load the database: " + ex.Message, "MARC - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
236 return false;
237 } finally {
238 lstResources.Sorted = true;
239 lstResources.EndUpdate();
240 }
241 }
242 private Boolean ImportDatabase(String fn) {
243 try {
244 lstResources.BeginUpdate();
245 lstResources.Sorted = false;
246 using (FileStream fs = File.OpenRead(fn)) {
247 BinaryReader br = new BinaryReader(fs, Encoding.UTF8);
248 if (br.ReadString() != "MARC") throw new Exception("This file is not a MARC database");
249 Byte version = br.ReadByte();
250 if (version == 2) {
251 br.ReadBytes(32);
252 Int32 c = br.ReadInt32();
253 for (int i = 0; i < c; i++) {
254 Int32 len = br.ReadInt32();
255 if (len == 0) continue;
256 ImportUpdate(br.ReadBytes(len), false);
257 }
258 } else if (version == 3) {
259 UInt32 len = Functions.FromBigEndian((UInt32)br.ReadInt32());
260 br.ReadBytes((int)len);
261 while (true) {
262 Byte[] lenbytes = br.ReadBytes(4);
263 if (lenbytes.Length == 0) break;
264 if (lenbytes.Length != 4) throw new Exception("Database truncated");
265 len = Functions.DecodeInt32BigEndian(lenbytes, 0);
266 ImportUpdate(br.ReadBytes((int)len), false);
267 }
268 } else {
269 throw new Exception("Unsupported database version");
270 }
271 br.Close();
272 return true;
273 }
274 } catch (Exception ex) {
275 Console.Error.WriteLine(ex.ToString());
276 MessageBox.Show(this, "Failed to import the database: " + ex.Message, "MARC - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
277 return false;
278 } finally {
279 lstResources.Sorted = true;
280 lstResources.EndUpdate();
281 }
282 }
283 private Boolean SaveDatabase(String fn) {
284 try {
285 if (File.Exists(fn) && fn != Database) {
286 if (DialogResult.No == MessageBox.Show(this, "The file " + fn + " exists. Are you sure you want to overwrite it?", "MARC - Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)) {
287 return false;
288 }
289 }
290 String tempfile = Path.GetTempFileName();
291 using (FileStream fs = File.Create(tempfile)) {
292 BinaryWriter wr = new BinaryWriter(fs, Encoding.UTF8);
293 wr.Write("MARC");
294 wr.Write((Byte)3); //Version
295 {
296 Hashtable metadata = new Hashtable();
297 ArrayList metakeys = new ArrayList();
298 Hashtable metakey = new Hashtable();
299 metakey.Add("key", SecretKey.SecretKey);
300 metakeys.Add(metakey);
301 metadata.Add("keys", metakeys);
302 ArrayList metapeers = new ArrayList();
303 foreach (String peer in Peers) {
304 Hashtable metapeer = new Hashtable();
305 metapeer.Add("address", peer);
306 metapeers.Add(metapeer);
307 }
308 metadata.Add("peers", metapeers);
309 ArrayList metablockedkeys = new ArrayList();
310 foreach (MARCKey peer in BlockedKeys) metablockedkeys.Add(peer.Bytes);
311 metadata.Add("blockedkeys", metablockedkeys);
312 metadata.Add("filterflags", Functions.EncodeInt32BigEndian((uint)FilterFlags));
313 Byte[] metabytes = MARCUpdate.EncodeValue(metadata);
314 wr.Write(Functions.EncodeInt32BigEndian((uint)metabytes.Length));
315 wr.Write(metabytes);
316 }
317 lock (Resources) {
318 foreach (MARCUpdate update in Resources.Values) {
319 Byte[] message = update.UpdateMessage;
320 if (message == null) {
321 wr.Write((Int32)0);
322 } else {
323 wr.Write((Int32)Functions.ToBigEndian((UInt32)message.Length));
324 wr.Write(message);
325 }
326 }
327 }
328 wr.Close();
329 File.Delete(fn);
330 File.Move(tempfile, fn);
331 Database = fn;
332 DatabaseSaved = true;
333 return true;
334 }
335 } catch (Exception ex) {
336 Console.Error.WriteLine(ex.ToString());
337 MessageBox.Show(this, "Failed to save the database: " + ex.Message, "MARC - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
338 return false;
339 }
340 }
341 #endregion
342
343 #region "Other database management"
344 private void CreateDatabase() {
345 if (!WarnDatabaseSaved()) return;
346 Database = null;
347 SecretKey = new ed25519keypair();
348 PublicKey = new MARCKey(SecretKey.PublicKey);
349 Resources = new Dictionary<MARCLabel, MARCUpdate>();
350 Peers = new List<string>();
351 BlockedKeys = new List<MARCKey>();
352 FilterFlags = ResourceTypeFilter.All & ~ResourceTypeFilter.Invalid;
353 Peers.Add("http://marc.ucis.ano/");
354 lstResources.Items.Clear();
355 UpdatePeersList();
356 DatabaseSaved = true;
357 }
358 public Boolean ImportUpdate(Byte[] update, Boolean quick) {
359 try {
360 MARCUpdate resource = MARCUpdate.Decode(update);
361 MARCLabel label = resource.Label;
362 MARCUpdate current;
363 if (!quick && IsResourceFiltered(resource)) return false;
364 lock (Resources) {
365 if (Resources.TryGetValue(label, out current)) {
366 if (current.Serial >= resource.Serial) return false;
367 if (!current.CanUpdate(resource.Key)) return false;
368 } else {
369 if (!quick && resource.Value == null) return false;
370 if (!quick && resource.Expired) return false;
371 current = null;
372 }
373 if (!quick && !resource.VerifySignature()) return false;
374 DatabaseSaved = false;
375 Resources[label] = resource;
376 }
377 if (InvokeRequired) {
378 Invoke((MethodInvoker)delegate() {
379 ResourceHasChanged(resource, current);
380 });
381 } else {
382 ResourceHasChanged(resource, current);
383 }
384 return true;
385 } catch (Exception ex) {
386 Console.Error.WriteLine(ex.ToString());
387 return false;
388 }
389 }
390 #endregion
391
392 public void ReplaceOrAddResource(MARCUpdate newres) {
393 MARCUpdate old;
394 lock (Resources) {
395 if (!Resources.TryGetValue(newres.Label, out old)) old = null;
396 Resources[newres.Label] = newres;
397 ResourceHasChanged(newres, old);
398 }
399 }
400 public void ResourceHasChanged(MARCUpdate newres, MARCUpdate oldres) {
401 Boolean selected = false;
402 if (oldres != null) {
403 selected = lstResources.SelectedItem == oldres;
404 lstResources.Items.Remove(oldres);
405 }
406 if (newres != null) {
407 AddResourceToListFiltered(newres);
408 if (selected) {
409 lstResources.SelectedItem = newres;
410 ShowResourceDetails(newres);
411 }
412 }
413 }
414
415 #region "Resource list box"
416 private void cmbResourceFilter_SelectedIndexChanged(object sender, EventArgs e) {
417 RefreshResourceList();
418 }
419 public void RefreshResourceList() {
420 lstResources.BeginUpdate();
421 lstResources.Sorted = false;
422 lstResources.Items.Clear();
423 lock (Resources) foreach (MARCUpdate update in Resources.Values) AddResourceToListFiltered(update);
424 lstResources.Sorted = true;
425 lstResources.EndUpdate();
426 }
427 private void AddResourceToListFiltered(MARCUpdate update) {
428 switch (cmbResourceFilter.SelectedIndex) {
429 case 1: //My resources
430 if (update.Key != PublicKey) return;
431 break;
432 case 2: //Filtered items
433 if (!IsResourceFiltered(update)) return;
434 break;
435 case 3: //Expired items
436 if (!update.Expired) return;
437 break;
438 case 4: //Domain names
439 if (update.Label.Bytes.Length < 1 || update.Label.Bytes[0] != 4) return;
440 break;
441 case 5: //IPv4 networks
442 if (update.Label.Bytes.Length != 6 || update.Label.Bytes[0] != 1) return;
443 break;
444 case 6: //IPv6 networks
445 if (update.Label.Bytes.Length != 18 || update.Label.Bytes[0] != 2) return;
446 break;
447 case 7: //AS numbers
448 if (update.Label.Bytes.Length != 5 || update.Label.Bytes[0] != 3) return;
449 break;
450 case 8: //Key info
451 if (update.Label.Bytes.Length != 33 || update.Label.Bytes[0] != 0) return;
452 break;
453 case 0: //All resources
454 default:
455 break;
456 }
457 lstResources.Items.Add(update);
458 }
459 private void lstResources_SelectedIndexChanged(object sender, EventArgs e) {
460 if (lstResources.SelectedItem == null) return;
461 ShowResourceDetails((MARCUpdate)lstResources.SelectedItem);
462 }
463 #endregion
464
465 #region "Resource details area"
466 private void ShowResourceDetails(MARCUpdate update) {
467 txtResourceKey.Text = update.Key.ToString();
468 txtResourceLabel.Text = update.Label.ToString();
469 txtResourceSerial.Text = update.Serial.ToString();
470 UInt32 tsnow = checked((UInt32)(DateTime.UtcNow - (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))).TotalSeconds);
471 UInt32 tslastyear = tsnow - 365 * 24 * 60 * 60;
472 String[] flags = null;
473 if (PublicKey == update.Key) UCIS.Util.ArrayUtil.Add(ref flags, "Owned");
474 else if (update.CanUpdate(PublicKey)) UCIS.Util.ArrayUtil.Add(ref flags, "Transferable");
475 if (update.Expired) UCIS.Util.ArrayUtil.Add(ref flags, "Expired");
476 if (flags == null || flags.Length == 0) UCIS.Util.ArrayUtil.Add(ref flags, "Claimed");
477 txtResourceStatus.Text = String.Join(", ", flags);
478 lvwResourceValue.SuspendLayout();
479 lvwResourceValue.Nodes.Clear();
480
481 if (update.Value is IDictionary) {
482 foreach (DictionaryEntry child in (IDictionary)update.Value) lvwResourceValue.Nodes.Add(AddResourceValueInTree(child.Key.ToString() + ": ", child.Value));
483 } else if (update.Value is ICollection) {
484 foreach (Object child in (ICollection)update.Value) lvwResourceValue.Nodes.Add(AddResourceValueInTree(String.Empty, child));
485 } else if (update.Value == null) {
486 lvwResourceValue.Nodes.Add("Null");
487 } else {
488 lvwResourceValue.Nodes.Add(update.Value.ToString());
489 }
490
491 lvwResourceValue.ResumeLayout();
492 }
493 private TreeNode AddResourceValueInTree(String prefix, Object value) {
494 TreeNode node = new TreeNode();
495 if (value is IDictionary) {
496 node.Text = prefix + "Dictionary";
497 foreach (DictionaryEntry child in (IDictionary)value) node.Nodes.Add(AddResourceValueInTree(child.Key.ToString() + ": ", child.Value));
498 } else if (value is ICollection) {
499 node.Text = prefix + "Collection";
500 foreach (Object child in (ICollection)value) node.Nodes.Add(AddResourceValueInTree(String.Empty, child));
501 } else if (value == null) {
502 node.Text = prefix + "Null";
503 } else {
504 node.Text = prefix + value.ToString();
505 }
506 node.Expand();
507 return node;
508 }
509 #endregion
510
511 #region "Menu bar"
512 private void settingsToolStripMenuItem_Click(object sender, EventArgs e) {
513 frmSettings form = new frmSettings();
514 form.MainForm = this;
515 form.ShowDialog(this);
516 }
517
518 public void newDatabaseToolStripMenuItem_Click(object sender, EventArgs e) {
519 CreateDatabase();
520 }
521 public void reloadDatabaseToolStripMenuItem_Click(object sender, EventArgs e) {
522 if (Database == null || !File.Exists(Database)) {
523 openDatabaseToolStripMenuItem_Click(sender, e);
524 } else {
525 LoadDatabase(Database);
526 }
527 }
528 public void saveDatabaseToolStripMenuItem_Click(object sender, EventArgs e) {
529 SaveDatabase();
530 }
531 public void saveDatabaseAsToolStripMenuItem_Click(object sender, EventArgs e) {
532 SaveDatabaseAs();
533 }
534 public void openDatabaseToolStripMenuItem_Click(object sender, EventArgs e) {
535 String fn = SelectDatabaseOpen("Open database");
536 if (fn == null) return;
537 LoadDatabase(fn);
538 }
539 public void importDatabaseToolStripMenuItem_Click(object sender, EventArgs e) {
540 String fn = SelectDatabaseOpen("Open database");
541 if (fn == null) return;
542 ImportDatabase(fn);
543 }
544 private void SynchronizeServerToolStripMenuItem_Click(object sender, EventArgs e) {
545 ToolStripMenuItem tsi = sender as ToolStripMenuItem;
546 frmSync form = new frmSync();
547 form.MainForm = this;
548 form.Hosts = (tsi == null || tsi.Tag == null) ? (IEnumerable<String>)Peers : new String[] { tsi.Tag.ToString() };
549 form.ShowDialog(this);
550 }
551
552 private void deleteSelectedToolStripMenuItem_Click(object sender, EventArgs e) {
553 MessageBox.Show(this, "This will delete the resources only from the local database. It may be retrieved again during synchronization.", "MARC - Delete resource", MessageBoxButtons.OK, MessageBoxIcon.Information);
554 List<MARCUpdate> ToDelete = new List<MARCUpdate>();
555 foreach (Object item in lstResources.SelectedItems) {
556 MARCUpdate update = (MARCUpdate)item;
557 if (Resources.Remove(update.Label)) ToDelete.Add(update);
558 DatabaseSaved = false;
559 }
560 lstResources.BeginUpdate();
561 lstResources.Sorted = false;
562 foreach (MARCUpdate item in ToDelete) ResourceHasChanged(null, item);
563 lstResources.Sorted = true;
564 lstResources.EndUpdate();
565 }
566
567 private void addKeyToFilterListToolStripMenuItem_Click(object sender, EventArgs e) {
568 if (lstResources.SelectedItems.Count == 0) return;
569 foreach (Object item in lstResources.SelectedItems) {
570 MARCUpdate update = (MARCUpdate)item;
571 if (BlockedKeys.Contains(update.Key)) continue;
572 BlockedKeys.Add(update.Key);
573 DatabaseSaved = false;
574 }
575 MessageBox.Show(this, "The selected key has been added to the filter list. Use the Settings window to delete all filtered items from the local database.", "MARC - Key filter", MessageBoxButtons.OK, MessageBoxIcon.Information);
576 }
577
578 private void addNewToolStripMenuItem_Click(object sender, EventArgs e) {
579 frmEditResource form = new frmEditResource();
580 form.MainForm = this;
581 form.ShowDialog(this);
582 }
583
584 private void editSelectedToolStripMenuItem_Click(object sender, EventArgs e) {
585 MARCUpdate resource = lstResources.SelectedItem as MARCUpdate;
586 if (resource == null) return;
587 frmEditResource form = new frmEditResource();
588 form.MainForm = this;
589 form.Label = resource.Label.Bytes;
590 form.Value = resource.Value as IDictionary;
591 form.ImportData();
592 form.ShowDialog(this);
593 }
594 #endregion
595
596 private void lstResources_DoubleClick(object sender, EventArgs e) {
597 editSelectedToolStripMenuItem_Click(sender, e);
598 }
599 }
600 }