Subversion Repositories general

Rev

Rev 1240 | Rev 1289 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1092 dev 1
using System;
2
using System.Drawing;
3
using System.Collections;
4
using System.Windows.Forms;
5
using System.IO;
6
using System.Net;
7
using System.Text;
8
using System.Text.RegularExpressions;
9
using System.Xml;
10
 
1201 dev 11
// GENERAL DESIGN
12
//
13
// Methods which are not running in the main application thread
14
// are not allowed no interact with GUI elemenents.
15
 
1092 dev 16
// FIXME:
17
//   - add soap validation
18
//   - icons for all items in the tree
19
//   - use pool of threads?
20
//   - do not store intermediate info, just row packets and the parsed fragments to display
21
//   - make the text fragment store switchable
1201 dev 22
//   - set locks during log writing (?)
1234 dev 23
//   - show '100 (Continue)' response info
1092 dev 24
namespace TCPproxy
25
{
1200 dev 26
	public class MainForm : Form
1092 dev 27
	{
1194 dev 28
		#region constants and settings
1197 dev 29
 
1199 dev 30
		private const int    RECENT_LENGTH          = 20;
31
		public  const string REGISTRY_KEY           = @"Software\Anatoli Klassen\TCPproxy";
32
		public  const string REGISTRY_RECENT_SUBKEY = "Recent Listenings";
1194 dev 33
 
1199 dev 34
		public  const byte   LOG_TYPE_BIN           = 1;
35
		public  const string LOG_BIN_HEADER         = "TCPproxy 1.0\n";
36
 
1194 dev 37
		#endregion constants and settings
38
 
1125 dev 39
		#region private fields
40
 
1194 dev 41
		private ListenForm   listenForm     = new ListenForm();
1125 dev 42
		private TcpListener  tcpListener    = null;
43
		private LogMessages  logMessages    = null;
44
		private Hashtable    treeNodes      = new Hashtable();
1194 dev 45
		private ArrayList    recentItems    = new ArrayList();
1125 dev 46
 
1194 dev 47
        private int          listenPort;
48
        private string       resendHost;
49
        private int          resendPort;
1125 dev 50
		private TcpShowMode  tcpShowMode    = TcpShowMode.ByDirection;
51
		private bool         autoExpand     = true;
1240 dev 52
		private bool         clearing       = false;
1125 dev 53
 
1194 dev 54
		private string       defaultCaption;
55
 
1125 dev 56
		#endregion private fields
57
 
58
		#region web forms fields
1194 dev 59
        private System.ComponentModel.IContainer components;
1200 dev 60
		private SaveFileDialog saveLogDialog;
61
        private StatusBarPanel connectionStatusBar;
62
        private MenuItem selectAllmenuItem;
63
        private MenuItem copyMenuItem;
64
        private ContextMenu viewContextMenu;
65
        private MenuItem closeConnectionMenuItem;
66
		private ImageList saveButtonImageList;
67
        private StatusBar statusBar;
68
        private ContextMenu messagesContextMenu;
69
		private ImageList treeImageList;
70
		private MenuItem wordWrapMenuItem;
1197 dev 71
        private MainMenu mainMenu;
72
        private MenuItem fileMenu;
73
        private MenuItem loadBinLogMenuItem;
74
        private MenuItem saveBinLogMenuItem;
75
        private MenuItem menuSeparator1;
76
        private MenuItem exitMenuItem;
77
        private MenuItem viewMenu;
78
        private MenuItem clearMainMenuItem;
79
        private MenuItem messagesMenu;
1201 dev 80
        private MenuItem saveLogMenuItem;
1197 dev 81
        private MenuItem saveTcoLogMenuItem;
82
        private MenuItem saveHttpLogMenuItem;
83
        private MenuItem saveXmlLogMenuItem;
84
        private MenuItem menuSeparator2;
85
        private MenuItem allMessagesMenuItem;
86
        private MenuItem importantMessagesMenuItem;
87
        private MenuItem infoMessagesMenuItem;
88
        private MenuItem menuSeparator3;
89
        private MenuItem tcpShowByDirectionMenuItem;
90
        private MenuItem tcpShowByTimeMenuItem;
91
        private MenuItem menuSeparator4;
1201 dev 92
        private MenuItem autoExpandMainMenuItem;
1197 dev 93
        private MenuItem wordWrapMainMenuItem;
94
        private MenuItem helpMenu;
1194 dev 95
        private Panel panel1;
96
        private Panel panel3;
97
        private Panel panel4;
98
        private ViewControl messagesBox;
99
        private Splitter splitter2;
100
        private ListBox logBox;
101
        private Splitter splitter1;
102
        private TreeView messageView;
1197 dev 103
        private MenuItem startMenuItem;
104
        private MenuItem stopMenuItem;
105
        private MenuItem menuSeparator5;
106
		private MenuItem recentListeningMenu;
107
		private MenuItem recentListeningNoItem;
1199 dev 108
		private SaveFileDialog saveBinLogDialog;
109
		private OpenFileDialog loadBinLogDialog;
1201 dev 110
		private MenuItem autoExpandMenuItem;
1197 dev 111
        private MenuItem aboutMenuItem;
1092 dev 112
		#endregion web forms fields
113
 
114
		#region Windows Form Designer generated code
115
		/// <summary>
116
		/// Required method for Designer support - do not modify
117
		/// the contents of this method with the code editor.
118
		/// </summary>
119
		private void InitializeComponent() {
1288 dev 120
            this.components=new System.ComponentModel.Container();
121
            System.ComponentModel.ComponentResourceManager resources=new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
122
            this.wordWrapMenuItem=new System.Windows.Forms.MenuItem();
123
            this.treeImageList=new System.Windows.Forms.ImageList(this.components);
124
            this.messagesContextMenu=new System.Windows.Forms.ContextMenu();
125
            this.selectAllmenuItem=new System.Windows.Forms.MenuItem();
126
            this.copyMenuItem=new System.Windows.Forms.MenuItem();
127
            this.statusBar=new System.Windows.Forms.StatusBar();
128
            this.connectionStatusBar=new System.Windows.Forms.StatusBarPanel();
129
            this.saveButtonImageList=new System.Windows.Forms.ImageList(this.components);
130
            this.closeConnectionMenuItem=new System.Windows.Forms.MenuItem();
131
            this.viewContextMenu=new System.Windows.Forms.ContextMenu();
132
            this.autoExpandMenuItem=new System.Windows.Forms.MenuItem();
133
            this.saveLogDialog=new System.Windows.Forms.SaveFileDialog();
134
            this.mainMenu=new System.Windows.Forms.MainMenu(this.components);
135
            this.fileMenu=new System.Windows.Forms.MenuItem();
136
            this.startMenuItem=new System.Windows.Forms.MenuItem();
137
            this.stopMenuItem=new System.Windows.Forms.MenuItem();
138
            this.recentListeningMenu=new System.Windows.Forms.MenuItem();
139
            this.recentListeningNoItem=new System.Windows.Forms.MenuItem();
140
            this.menuSeparator5=new System.Windows.Forms.MenuItem();
141
            this.loadBinLogMenuItem=new System.Windows.Forms.MenuItem();
142
            this.saveBinLogMenuItem=new System.Windows.Forms.MenuItem();
143
            this.menuSeparator1=new System.Windows.Forms.MenuItem();
144
            this.saveLogMenuItem=new System.Windows.Forms.MenuItem();
145
            this.saveTcoLogMenuItem=new System.Windows.Forms.MenuItem();
146
            this.saveHttpLogMenuItem=new System.Windows.Forms.MenuItem();
147
            this.saveXmlLogMenuItem=new System.Windows.Forms.MenuItem();
148
            this.menuSeparator2=new System.Windows.Forms.MenuItem();
149
            this.exitMenuItem=new System.Windows.Forms.MenuItem();
150
            this.viewMenu=new System.Windows.Forms.MenuItem();
151
            this.clearMainMenuItem=new System.Windows.Forms.MenuItem();
152
            this.messagesMenu=new System.Windows.Forms.MenuItem();
153
            this.allMessagesMenuItem=new System.Windows.Forms.MenuItem();
154
            this.infoMessagesMenuItem=new System.Windows.Forms.MenuItem();
155
            this.importantMessagesMenuItem=new System.Windows.Forms.MenuItem();
156
            this.menuSeparator3=new System.Windows.Forms.MenuItem();
157
            this.tcpShowByDirectionMenuItem=new System.Windows.Forms.MenuItem();
158
            this.tcpShowByTimeMenuItem=new System.Windows.Forms.MenuItem();
159
            this.menuSeparator4=new System.Windows.Forms.MenuItem();
160
            this.autoExpandMainMenuItem=new System.Windows.Forms.MenuItem();
161
            this.wordWrapMainMenuItem=new System.Windows.Forms.MenuItem();
162
            this.helpMenu=new System.Windows.Forms.MenuItem();
163
            this.aboutMenuItem=new System.Windows.Forms.MenuItem();
164
            this.panel1=new System.Windows.Forms.Panel();
165
            this.panel3=new System.Windows.Forms.Panel();
166
            this.panel4=new System.Windows.Forms.Panel();
167
            this.splitter2=new System.Windows.Forms.Splitter();
168
            this.logBox=new System.Windows.Forms.ListBox();
169
            this.splitter1=new System.Windows.Forms.Splitter();
170
            this.messageView=new System.Windows.Forms.TreeView();
171
            this.saveBinLogDialog=new System.Windows.Forms.SaveFileDialog();
172
            this.loadBinLogDialog=new System.Windows.Forms.OpenFileDialog();
173
            this.messagesBox=new TCPproxy.ViewControl();
174
            ((System.ComponentModel.ISupportInitialize)(this.connectionStatusBar)).BeginInit();
175
            this.panel1.SuspendLayout();
176
            this.panel3.SuspendLayout();
177
            this.panel4.SuspendLayout();
178
            this.SuspendLayout();
179
            // 
180
            // wordWrapMenuItem
181
            // 
182
            this.wordWrapMenuItem.Index=2;
183
            this.wordWrapMenuItem.Text="Word &Wrap";
184
            this.wordWrapMenuItem.Click+=new System.EventHandler(this.wordWrapMenuItem_Click);
185
            // 
186
            // treeImageList
187
            // 
188
            this.treeImageList.ImageStream=((System.Windows.Forms.ImageListStreamer)(resources.GetObject("treeImageList.ImageStream")));
189
            this.treeImageList.TransparentColor=System.Drawing.Color.Magenta;
190
            this.treeImageList.Images.SetKeyName(0, "");
191
            this.treeImageList.Images.SetKeyName(1, "");
192
            this.treeImageList.Images.SetKeyName(2, "");
193
            // 
194
            // messagesContextMenu
195
            // 
196
            this.messagesContextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1194 dev 197
            this.selectAllmenuItem,
198
            this.copyMenuItem,
199
            this.wordWrapMenuItem});
1288 dev 200
            // 
201
            // selectAllmenuItem
202
            // 
203
            this.selectAllmenuItem.Index=0;
204
            this.selectAllmenuItem.Shortcut=System.Windows.Forms.Shortcut.CtrlA;
205
            this.selectAllmenuItem.Text="Select &All";
206
            this.selectAllmenuItem.Click+=new System.EventHandler(this.selectAllMenuItem_Click);
207
            // 
208
            // copyMenuItem
209
            // 
210
            this.copyMenuItem.Index=1;
211
            this.copyMenuItem.Shortcut=System.Windows.Forms.Shortcut.CtrlC;
212
            this.copyMenuItem.Text="&Copy";
213
            this.copyMenuItem.Click+=new System.EventHandler(this.copyMenuItem_Click);
214
            // 
215
            // statusBar
216
            // 
217
            this.statusBar.Location=new System.Drawing.Point(0, 279);
218
            this.statusBar.Name="statusBar";
219
            this.statusBar.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
1194 dev 220
            this.connectionStatusBar});
1288 dev 221
            this.statusBar.ShowPanels=true;
222
            this.statusBar.Size=new System.Drawing.Size(780, 22);
223
            this.statusBar.TabIndex=0;
224
            // 
225
            // connectionStatusBar
226
            // 
227
            this.connectionStatusBar.AutoSize=System.Windows.Forms.StatusBarPanelAutoSize.Spring;
228
            this.connectionStatusBar.Name="connectionStatusBar";
229
            this.connectionStatusBar.Width=764;
230
            // 
231
            // saveButtonImageList
232
            // 
233
            this.saveButtonImageList.ImageStream=((System.Windows.Forms.ImageListStreamer)(resources.GetObject("saveButtonImageList.ImageStream")));
234
            this.saveButtonImageList.TransparentColor=System.Drawing.Color.Magenta;
235
            this.saveButtonImageList.Images.SetKeyName(0, "");
236
            // 
237
            // closeConnectionMenuItem
238
            // 
239
            this.closeConnectionMenuItem.Index=0;
240
            this.closeConnectionMenuItem.Text="&Close connection";
241
            this.closeConnectionMenuItem.Click+=new System.EventHandler(this.closeConnectionMenuItem_Click);
242
            // 
243
            // viewContextMenu
244
            // 
245
            this.viewContextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1201 dev 246
            this.closeConnectionMenuItem,
247
            this.autoExpandMenuItem});
1288 dev 248
            // 
249
            // autoExpandMenuItem
250
            // 
251
            this.autoExpandMenuItem.Index=1;
252
            this.autoExpandMenuItem.Text="Auto E&xpand";
253
            this.autoExpandMenuItem.Click+=new System.EventHandler(this.autoExpandMenuItem_Click);
254
            // 
255
            // saveLogDialog
256
            // 
257
            this.saveLogDialog.DefaultExt="txt";
258
            this.saveLogDialog.Filter="Text Files (*.txt)|*.txt|All Files|*.*";
259
            this.saveLogDialog.Title="Save Log";
260
            // 
261
            // mainMenu
262
            // 
263
            this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1199 dev 264
            this.fileMenu,
265
            this.viewMenu,
266
            this.helpMenu});
1288 dev 267
            // 
268
            // fileMenu
269
            // 
270
            this.fileMenu.Index=0;
271
            this.fileMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1199 dev 272
            this.startMenuItem,
273
            this.stopMenuItem,
274
            this.recentListeningMenu,
275
            this.menuSeparator5,
276
            this.loadBinLogMenuItem,
277
            this.saveBinLogMenuItem,
278
            this.menuSeparator1,
1201 dev 279
            this.saveLogMenuItem,
1199 dev 280
            this.saveTcoLogMenuItem,
281
            this.saveHttpLogMenuItem,
282
            this.saveXmlLogMenuItem,
283
            this.menuSeparator2,
284
            this.exitMenuItem});
1288 dev 285
            this.fileMenu.Text="&File";
286
            // 
287
            // startMenuItem
288
            // 
289
            this.startMenuItem.Index=0;
290
            this.startMenuItem.Text="&Start...";
291
            this.startMenuItem.Click+=new System.EventHandler(this.startMenuItem_Click);
292
            // 
293
            // stopMenuItem
294
            // 
295
            this.stopMenuItem.Enabled=false;
296
            this.stopMenuItem.Index=1;
297
            this.stopMenuItem.Text="S&top";
298
            this.stopMenuItem.Click+=new System.EventHandler(this.stopMenuItem_Click);
299
            // 
300
            // recentListeningMenu
301
            // 
302
            this.recentListeningMenu.Index=2;
303
            this.recentListeningMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1199 dev 304
            this.recentListeningNoItem});
1288 dev 305
            this.recentListeningMenu.Text="&Recent Listenings";
306
            // 
307
            // recentListeningNoItem
308
            // 
309
            this.recentListeningNoItem.Enabled=false;
310
            this.recentListeningNoItem.Index=0;
311
            this.recentListeningNoItem.Text="(no items)";
312
            // 
313
            // menuSeparator5
314
            // 
315
            this.menuSeparator5.Index=3;
316
            this.menuSeparator5.Text="-";
317
            // 
318
            // loadBinLogMenuItem
319
            // 
320
            this.loadBinLogMenuItem.Index=4;
321
            this.loadBinLogMenuItem.Text="&Load Bin Log...";
322
            this.loadBinLogMenuItem.Click+=new System.EventHandler(this.loadBinLogMenuItem_Click);
323
            // 
324
            // saveBinLogMenuItem
325
            // 
326
            this.saveBinLogMenuItem.Index=5;
327
            this.saveBinLogMenuItem.Text="&Save Bin Log...";
328
            this.saveBinLogMenuItem.Click+=new System.EventHandler(this.saveBinLogMenuItem_Click);
329
            // 
330
            // menuSeparator1
331
            // 
332
            this.menuSeparator1.Index=6;
333
            this.menuSeparator1.Text="-";
334
            // 
335
            // saveLogMenuItem
336
            // 
337
            this.saveLogMenuItem.Index=7;
338
            this.saveLogMenuItem.Text="Save Log Messa&ges...";
339
            this.saveLogMenuItem.Click+=new System.EventHandler(this.saveLogMenuItem_Click);
340
            // 
341
            // saveTcoLogMenuItem
342
            // 
343
            this.saveTcoLogMenuItem.Index=8;
344
            this.saveTcoLogMenuItem.Text="Save T&CP Log...";
345
            this.saveTcoLogMenuItem.Click+=new System.EventHandler(this.saveTcpMenuItem_Click);
346
            // 
347
            // saveHttpLogMenuItem
348
            // 
349
            this.saveHttpLogMenuItem.Index=9;
350
            this.saveHttpLogMenuItem.Text="Save Htt&p Log...";
351
            this.saveHttpLogMenuItem.Click+=new System.EventHandler(this.saveHttpMenuItem_Click);
352
            // 
353
            // saveXmlLogMenuItem
354
            // 
355
            this.saveXmlLogMenuItem.Index=10;
356
            this.saveXmlLogMenuItem.Text="Save X&ML Log...";
357
            this.saveXmlLogMenuItem.Click+=new System.EventHandler(this.saveXmlMenuItem_Click);
358
            // 
359
            // menuSeparator2
360
            // 
361
            this.menuSeparator2.Index=11;
362
            this.menuSeparator2.Text="-";
363
            // 
364
            // exitMenuItem
365
            // 
366
            this.exitMenuItem.Index=12;
367
            this.exitMenuItem.Text="E&xit";
368
            // 
369
            // viewMenu
370
            // 
371
            this.viewMenu.Index=1;
372
            this.viewMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1199 dev 373
            this.clearMainMenuItem,
374
            this.messagesMenu,
375
            this.menuSeparator3,
376
            this.tcpShowByDirectionMenuItem,
377
            this.tcpShowByTimeMenuItem,
378
            this.menuSeparator4,
1201 dev 379
            this.autoExpandMainMenuItem,
1199 dev 380
            this.wordWrapMainMenuItem});
1288 dev 381
            this.viewMenu.Text="&View";
382
            // 
383
            // clearMainMenuItem
384
            // 
385
            this.clearMainMenuItem.Index=0;
386
            this.clearMainMenuItem.Text="&Clear";
387
            this.clearMainMenuItem.Click+=new System.EventHandler(this.clearMenuItem_Click);
388
            // 
389
            // messagesMenu
390
            // 
391
            this.messagesMenu.Index=1;
392
            this.messagesMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1199 dev 393
            this.allMessagesMenuItem,
394
            this.infoMessagesMenuItem,
395
            this.importantMessagesMenuItem});
1288 dev 396
            this.messagesMenu.Text="&Messages";
397
            // 
398
            // allMessagesMenuItem
399
            // 
400
            this.allMessagesMenuItem.Checked=true;
401
            this.allMessagesMenuItem.Index=0;
402
            this.allMessagesMenuItem.Text="&All";
403
            this.allMessagesMenuItem.Click+=new System.EventHandler(this.messagesMenuItem_Click);
404
            // 
405
            // infoMessagesMenuItem
406
            // 
407
            this.infoMessagesMenuItem.Index=1;
408
            this.infoMessagesMenuItem.Text="&Info";
409
            this.infoMessagesMenuItem.Click+=new System.EventHandler(this.messagesMenuItem_Click);
410
            // 
411
            // importantMessagesMenuItem
412
            // 
413
            this.importantMessagesMenuItem.Index=2;
414
            this.importantMessagesMenuItem.Text="I&mportant";
415
            this.importantMessagesMenuItem.Click+=new System.EventHandler(this.messagesMenuItem_Click);
416
            // 
417
            // menuSeparator3
418
            // 
419
            this.menuSeparator3.Index=2;
420
            this.menuSeparator3.Text="-";
421
            // 
422
            // tcpShowByDirectionMenuItem
423
            // 
424
            this.tcpShowByDirectionMenuItem.Checked=true;
425
            this.tcpShowByDirectionMenuItem.Index=3;
426
            this.tcpShowByDirectionMenuItem.Text="TCP Show by &Direction";
427
            this.tcpShowByDirectionMenuItem.Click+=new System.EventHandler(this.tcpShowByDirectionMenuItem_Click);
428
            // 
429
            // tcpShowByTimeMenuItem
430
            // 
431
            this.tcpShowByTimeMenuItem.Index=4;
432
            this.tcpShowByTimeMenuItem.Text="TCP Show by &Time";
433
            this.tcpShowByTimeMenuItem.Click+=new System.EventHandler(this.tcpShowByTimeMenuItem_Click);
434
            // 
435
            // menuSeparator4
436
            // 
437
            this.menuSeparator4.Index=5;
438
            this.menuSeparator4.Text="-";
439
            // 
440
            // autoExpandMainMenuItem
441
            // 
442
            this.autoExpandMainMenuItem.Index=6;
443
            this.autoExpandMainMenuItem.Text="Auto E&xpand";
444
            this.autoExpandMainMenuItem.Click+=new System.EventHandler(this.autoExpandMenuItem_Click);
445
            // 
446
            // wordWrapMainMenuItem
447
            // 
448
            this.wordWrapMainMenuItem.Index=7;
449
            this.wordWrapMainMenuItem.Text="Word &Wrap";
450
            this.wordWrapMainMenuItem.Click+=new System.EventHandler(this.wordWrapMenuItem_Click);
451
            // 
452
            // helpMenu
453
            // 
454
            this.helpMenu.Index=2;
455
            this.helpMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
1199 dev 456
            this.aboutMenuItem});
1288 dev 457
            this.helpMenu.Text="&Help";
458
            // 
459
            // aboutMenuItem
460
            // 
461
            this.aboutMenuItem.Index=0;
462
            this.aboutMenuItem.Text="&About...";
463
            this.aboutMenuItem.Click+=new System.EventHandler(this.aboutMenuItem_Click);
464
            // 
465
            // panel1
466
            // 
467
            this.panel1.Controls.Add(this.panel3);
468
            this.panel1.Dock=System.Windows.Forms.DockStyle.Fill;
469
            this.panel1.Location=new System.Drawing.Point(0, 0);
470
            this.panel1.Name="panel1";
471
            this.panel1.Size=new System.Drawing.Size(780, 279);
472
            this.panel1.TabIndex=11;
473
            // 
474
            // panel3
475
            // 
476
            this.panel3.Controls.Add(this.panel4);
477
            this.panel3.Controls.Add(this.splitter1);
478
            this.panel3.Controls.Add(this.messageView);
479
            this.panel3.Dock=System.Windows.Forms.DockStyle.Fill;
480
            this.panel3.Location=new System.Drawing.Point(0, 0);
481
            this.panel3.Name="panel3";
482
            this.panel3.Size=new System.Drawing.Size(780, 279);
483
            this.panel3.TabIndex=5;
484
            // 
485
            // panel4
486
            // 
487
            this.panel4.Controls.Add(this.messagesBox);
488
            this.panel4.Controls.Add(this.splitter2);
489
            this.panel4.Controls.Add(this.logBox);
490
            this.panel4.Dock=System.Windows.Forms.DockStyle.Fill;
491
            this.panel4.Location=new System.Drawing.Point(163, 0);
492
            this.panel4.Name="panel4";
493
            this.panel4.Size=new System.Drawing.Size(617, 279);
494
            this.panel4.TabIndex=13;
495
            // 
496
            // splitter2
497
            // 
498
            this.splitter2.Dock=System.Windows.Forms.DockStyle.Bottom;
499
            this.splitter2.Location=new System.Drawing.Point(0, 208);
500
            this.splitter2.Name="splitter2";
501
            this.splitter2.Size=new System.Drawing.Size(617, 3);
502
            this.splitter2.TabIndex=9;
503
            this.splitter2.TabStop=false;
504
            // 
505
            // logBox
506
            // 
507
            this.logBox.Dock=System.Windows.Forms.DockStyle.Bottom;
508
            this.logBox.Font=new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
509
            this.logBox.HorizontalScrollbar=true;
510
            this.logBox.ItemHeight=16;
511
            this.logBox.Location=new System.Drawing.Point(0, 211);
512
            this.logBox.Name="logBox";
513
            this.logBox.ScrollAlwaysVisible=true;
514
            this.logBox.Size=new System.Drawing.Size(617, 68);
515
            this.logBox.TabIndex=8;
516
            // 
517
            // splitter1
518
            // 
519
            this.splitter1.Location=new System.Drawing.Point(160, 0);
520
            this.splitter1.Name="splitter1";
521
            this.splitter1.Size=new System.Drawing.Size(3, 279);
522
            this.splitter1.TabIndex=12;
523
            this.splitter1.TabStop=false;
524
            // 
525
            // messageView
526
            // 
527
            this.messageView.ContextMenu=this.viewContextMenu;
528
            this.messageView.Dock=System.Windows.Forms.DockStyle.Left;
529
            this.messageView.HideSelection=false;
530
            this.messageView.ImageIndex=0;
531
            this.messageView.ImageList=this.treeImageList;
532
            this.messageView.Location=new System.Drawing.Point(0, 0);
533
            this.messageView.Name="messageView";
534
            this.messageView.SelectedImageIndex=0;
535
            this.messageView.Size=new System.Drawing.Size(160, 279);
536
            this.messageView.TabIndex=11;
537
            this.messageView.AfterSelect+=new System.Windows.Forms.TreeViewEventHandler(this.messageView_AfterSelect);
538
            this.messageView.MouseDown+=new System.Windows.Forms.MouseEventHandler(this.messageView_MouseDown);
539
            this.messageView.BeforeSelect+=new System.Windows.Forms.TreeViewCancelEventHandler(this.messageView_BeforeSelect);
540
            // 
541
            // saveBinLogDialog
542
            // 
543
            this.saveBinLogDialog.DefaultExt="tcp";
544
            this.saveBinLogDialog.Filter="TCP Logs (*.bin)|*.bin|All Files|*.*";
545
            this.saveBinLogDialog.Title="Save Binary Log";
546
            // 
547
            // loadBinLogDialog
548
            // 
549
            this.loadBinLogDialog.FileName="openFileDialog1";
550
            this.loadBinLogDialog.Filter="TCP Logs (*.bin)|*.bin|All Files|*.*";
551
            this.loadBinLogDialog.Title="Load Binary Log";
552
            // 
553
            // messagesBox
554
            // 
555
            this.messagesBox.ContextMenu=this.messagesContextMenu;
556
            this.messagesBox.Dock=System.Windows.Forms.DockStyle.Fill;
557
            this.messagesBox.Font=new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
558
            this.messagesBox.Location=new System.Drawing.Point(0, 0);
559
            this.messagesBox.Name="messagesBox";
560
            this.messagesBox.Size=new System.Drawing.Size(617, 208);
561
            this.messagesBox.TabIndex=7;
562
            this.messagesBox.WordWrap=true;
563
            // 
564
            // MainForm
565
            // 
566
            this.AutoScaleBaseSize=new System.Drawing.Size(5, 13);
567
            this.ClientSize=new System.Drawing.Size(780, 301);
568
            this.Controls.Add(this.panel1);
569
            this.Controls.Add(this.statusBar);
570
            this.Menu=this.mainMenu;
571
            this.MinimumSize=new System.Drawing.Size(400, 200);
572
            this.Name="MainForm";
573
            this.StartPosition=System.Windows.Forms.FormStartPosition.Manual;
574
            this.Text="TCPproxy";
575
            ((System.ComponentModel.ISupportInitialize)(this.connectionStatusBar)).EndInit();
576
            this.panel1.ResumeLayout(false);
577
            this.panel3.ResumeLayout(false);
578
            this.panel4.ResumeLayout(false);
579
            this.ResumeLayout(false);
1194 dev 580
 
1092 dev 581
		}
582
		#endregion
583
 
584
		#region windows forms methods
585
		public MainForm()
586
		{
587
			InitializeComponent();
588
			logMessages = new LogMessages(logBox);
1194 dev 589
			try {
590
				LoadFromRegistry();
591
				LoadRecentItemsFromRegistry();
592
			}
593
			catch(Exception) {}
594
 
595
			// update visual elements
596
			UpdateMessagesMenuItems();
597
 
598
			if(tcpShowMode == TcpShowMode.ByDirection) {
599
				tcpShowByDirectionMenuItem.Checked = true;
600
				tcpShowByTimeMenuItem.Checked      = false;
601
			}
602
			else {
603
				tcpShowByDirectionMenuItem.Checked = false;
604
				tcpShowByTimeMenuItem.Checked      = true;
605
			}
606
 
1201 dev 607
			autoExpandMenuItem.Checked     = autoExpand;
608
			autoExpandMainMenuItem.Checked = autoExpand;
609
			wordWrapMenuItem.Checked       = messagesBox.WordWrap;
610
			wordWrapMainMenuItem.Checked   = messagesBox.WordWrap;
1194 dev 611
 
612
			// save default values
613
			defaultCaption = this.Text;
1092 dev 614
		}
615
 
1194 dev 616
		protected override void Dispose(bool disposing)
1092 dev 617
		{
1240 dev 618
			clearing = true;
619
 
1194 dev 620
			if(tcpListener != null) {
1092 dev 621
				tcpListener.StopListening();    // stop listening
622
				tcpListener.CancelAll();        // cancel all open connections
623
			}
624
 
1194 dev 625
			// save settings
1197 dev 626
			SaveToRegistry();
1194 dev 627
			SaveRecentItemsToRegistry();
1092 dev 628
 
629
			if( disposing )
630
			{
631
				if (components != null)
632
				{
633
					components.Dispose();
634
				}
635
			}
636
			base.Dispose( disposing );
1232 dev 637
 
638
			ThreadDebugger.PrintStatus();
1092 dev 639
		}
640
 
641
		[STAThread]
642
		static void Main()
643
		{
644
			Application.Run(new MainForm());
645
		}
646
 
1194 dev 647
		private void startMenuItem_Click(object sender, System.EventArgs e)
648
		{
649
			IPAddress resendIp;
650
 
1197 dev 651
			if(!listenForm.Execute(this,
1194 dev 652
				ref listenPort, ref resendHost, out resendIp, ref resendPort)) return;
653
 
654
			StartListening(listenPort, resendIp, resendPort);
655
		}
656
 
657
		private void stopMenuItem_Click(object sender, System.EventArgs e)
1092 dev 658
		{
1199 dev 659
			StopListening();
1092 dev 660
		}
661
 
1194 dev 662
		private void clearMenuItem_Click(object sender, System.EventArgs e)
1092 dev 663
		{
1199 dev 664
			ClearAll();
1092 dev 665
		}
666
 
667
		private void selectAllMenuItem_Click(object sender, System.EventArgs e)
668
		{
669
			messagesBox.SelectAll();
670
		}
671
 
672
		private void copyMenuItem_Click(object sender, System.EventArgs e)
673
		{
674
			string sel = messagesBox.SelectedText;
675
			if(sel != null) Clipboard.SetDataObject(sel);
676
		}
677
 
678
		private void wordWrapMenuItem_Click(object sender, System.EventArgs e)
679
		{
1194 dev 680
			messagesBox.WordWrap         = !messagesBox.WordWrap;
681
			wordWrapMenuItem.Checked     = messagesBox.WordWrap;
682
			wordWrapMainMenuItem.Checked = messagesBox.WordWrap;
1092 dev 683
		}
684
 
685
		private void autoExpandMenuItem_Click(object sender, System.EventArgs e)
686
		{
1201 dev 687
			autoExpand                     = !autoExpand;
688
			autoExpandMenuItem.Checked     = autoExpand;
689
			autoExpandMainMenuItem.Checked = autoExpand;
1092 dev 690
		}
691
 
1194 dev 692
		private void aboutMenuItem_Click(object sender, EventArgs e)
693
		{
694
			(new AboutForm()).ShowDialog(this);
695
		}
696
 
1200 dev 697
		private void messageView_BeforeSelect(object sender, TreeViewCancelEventArgs e)
1092 dev 698
		{
1288 dev 699
            messageView.Tag = null; // clear the right-click item
700
 
1092 dev 701
			if(messageView.SelectedNode == null) return;
702
 
703
			object tag = messageView.SelectedNode.Tag;
704
			if(tag is TreeNodeData)
705
			{
706
				TreeNodeData data = (TreeNodeData)tag;
707
				data.SaveViewState();
708
			}
709
		}
710
 
1200 dev 711
		private void messageView_AfterSelect(object sender, TreeViewEventArgs e)
1092 dev 712
		{
713
			if(messageView.SelectedNode == null) return;
714
 
715
			object tag = messageView.SelectedNode.Tag;
716
			if(tag is TreeNodeData)
717
			{
718
				TreeNodeData data = (TreeNodeData)tag;
719
				data.Show();
720
			}
721
		}
722
 
723
		private void closeConnectionMenuItem_Click(object sender, System.EventArgs e)
724
		{
1288 dev 725
            TreeNode node;
726
            if(messageView.Tag != null) {
727
                node = messageView.GetNodeAt((Point)messageView.Tag);
728
            }
729
            else {
730
                node = messageView.SelectedNode;
731
            }
1092 dev 732
 
1288 dev 733
			if(node != null)
734
            {
735
                object tag = node.Tag;
736
			    if(tag is TcpNodeData)
737
				    CloseTcpConnection(((TcpNodeData)tag).Tcp);
738
			    else if(tag is TcpNodeData)
739
				    CloseTcpConnection(((TcpNodeData)node.Parent.Tag).Tcp);
740
			    else if(tag is XmlNodeData)
741
				    CloseTcpConnection(((TcpNodeData)node.Parent.Parent.Tag).Tcp);
742
            }
1092 dev 743
		}
744
 
1288 dev 745
        private void messageView_MouseDown(object sender, MouseEventArgs e)
746
        {
747
            if(e.Button == MouseButtons.Right) {
748
                messageView.Tag = new Point(e.X, e.Y); // save mouse click coord
749
            }
750
        }
751
 
1092 dev 752
		private void tcpShowByDirectionMenuItem_Click(object sender, System.EventArgs e)
753
		{
754
			tcpShowMode = TcpShowMode.ByDirection;
1194 dev 755
			tcpShowByDirectionMenuItem.Checked = true;
756
			tcpShowByTimeMenuItem.Checked      = false;
1092 dev 757
 
1288 dev 758
            TreeNode node;
759
            if(messageView.Tag != null) {
760
                node = messageView.GetNodeAt((Point)messageView.Tag);
761
            }
762
            else {
763
                node = messageView.SelectedNode;
764
            }
1092 dev 765
 
1288 dev 766
			if(node != null)
767
            {
768
			    object tag = node.Tag;
769
			    if(tag is TcpNodeData)
770
				    UpdateTcpNodeInternal(((TcpNodeData)tag).Tcp);
771
            }
1092 dev 772
		}
773
 
774
		private void tcpShowByTimeMenuItem_Click(object sender, System.EventArgs e)
775
		{
776
			tcpShowMode = TcpShowMode.ByTime;
1194 dev 777
			tcpShowByDirectionMenuItem.Checked = false;
778
			tcpShowByTimeMenuItem.Checked      = true;
1092 dev 779
 
780
			if(messageView.SelectedNode == null) return;
781
 
1288 dev 782
            TreeNode node;
783
            if(messageView.Tag != null) {
784
                node = messageView.GetNodeAt((Point)messageView.Tag);
785
            }
786
            else {
787
                node = messageView.SelectedNode;
788
            }
789
 
790
			if(node != null)
791
            {
792
			    object tag = node.Tag;
793
			    if(tag is TcpNodeData)
794
				    UpdateTcpNodeInternal(((TcpNodeData)tag).Tcp);
795
            }
1092 dev 796
		}
797
 
798
		private void saveLogMenuItem_Click(object sender, System.EventArgs e)
799
		{
1201 dev 800
			if(saveLogDialog.ShowDialog() == DialogResult.OK) {
801
				try {
802
					SaveLog(saveLogDialog.FileName);
803
				}
804
				catch(Exception ex) {
805
					MessageBox.Show("Cannot save log to file " + saveLogDialog.FileName
806
						+ ":\n" + ex.Message, "TCPproxy",
807
						MessageBoxButtons.OK, MessageBoxIcon.Error);
808
				}
1092 dev 809
			}
810
		}
811
 
812
		private void saveTcpMenuItem_Click(object sender, System.EventArgs e)
813
		{
1201 dev 814
			if(saveLogDialog.ShowDialog() == DialogResult.OK) {
815
				try {
816
					SaveTcp(saveLogDialog.FileName);
817
				}
818
				catch(Exception ex) {
819
					MessageBox.Show("Cannot save TCP log to file " + saveLogDialog.FileName
820
						+ ":\n" + ex.Message, "TCPproxy",
821
						MessageBoxButtons.OK, MessageBoxIcon.Error);
822
				}
1092 dev 823
			}
824
		}
825
 
826
		private void saveHttpMenuItem_Click(object sender, System.EventArgs e)
827
		{
1201 dev 828
			if(saveLogDialog.ShowDialog() == DialogResult.OK) {
829
				try {
830
					SaveHttp(saveLogDialog.FileName);
831
				}
832
				catch(Exception ex) {
833
					MessageBox.Show("Cannot save HTTP log to file " + saveLogDialog.FileName
834
						+ ":\n" + ex.Message, "TCPproxy",
835
						MessageBoxButtons.OK, MessageBoxIcon.Error);
836
				}
1092 dev 837
			}
838
		}
839
 
840
		private void saveXmlMenuItem_Click(object sender, System.EventArgs e)
841
		{
1201 dev 842
			if(saveLogDialog.ShowDialog() == DialogResult.OK) {
843
				try {
844
					SaveXml(saveLogDialog.FileName);
845
				}
846
				catch(Exception ex) {
847
					MessageBox.Show("Cannot save XML log to file " + saveLogDialog.FileName
848
						+ ":\n" + ex.Message, "TCPproxy",
849
						MessageBoxButtons.OK, MessageBoxIcon.Error);
850
				}
1092 dev 851
			}
852
		}
853
 
1199 dev 854
		private void saveBinLogMenuItem_Click(object sender, EventArgs e)
855
		{
1201 dev 856
			if(saveBinLogDialog.ShowDialog() == DialogResult.OK) {
857
				try {
858
					SaveBinLog(saveBinLogDialog.FileName);
859
				}
860
				catch(Exception ex) {
861
					MessageBox.Show("Cannot save binary log to file " + saveBinLogDialog.FileName
862
						+ ":\n" + ex.Message, "TCPproxy",
863
						MessageBoxButtons.OK, MessageBoxIcon.Error);
864
				}
865
			}
1199 dev 866
		}
867
 
868
		private void loadBinLogMenuItem_Click(object sender, EventArgs e)
869
		{
1201 dev 870
			if(loadBinLogDialog.ShowDialog() == DialogResult.OK) {
871
				try {
872
					LoadBinLog(loadBinLogDialog.FileName);
873
				}
874
				catch(Exception ex) {
875
					MessageBox.Show("Cannot load binary log from file " + loadBinLogDialog.FileName
876
						+ ":\n" + ex.Message, "TCPproxy",
877
						MessageBoxButtons.OK, MessageBoxIcon.Error);
878
				}
879
			}
1199 dev 880
		}
881
 
1194 dev 882
		private void messagesMenuItem_Click(object sender, EventArgs e)
1092 dev 883
		{
1194 dev 884
			if(sender == importantMessagesMenuItem)
885
				logMessages.Level = LogLevel.Important;
886
			else if(sender == infoMessagesMenuItem)
887
				logMessages.Level = LogLevel.Info;
888
			else
889
				logMessages.Level = LogLevel.Debug;
1092 dev 890
 
1194 dev 891
			UpdateMessagesMenuItems();
892
		}
1092 dev 893
 
1194 dev 894
		private void recentMenuItem_Click(object sender, EventArgs e)
895
		{
1238 dev 896
			MenuItem   menuItem   = (MenuItem)sender;
897
			RecentItem recentItem = (RecentItem)recentItems[recentItems.Count - menuItem.Index - 1];
1194 dev 898
			IPAddress  resendIp;
899
 
900
			this.listenPort = recentItem.ListenPort;
901
			this.resendHost = recentItem.ResendHost;
902
			this.resendPort = recentItem.ResendPort;
1197 dev 903
 
1194 dev 904
			try
905
			{
906
				resendIp = HostUtils.ResendHostToIp(resendHost);
907
			}
908
			catch(Exception ex)
909
			{
1201 dev 910
				MessageBox.Show("Cannot get host IP: " + ex.Message, "TCPproxy",
911
					MessageBoxButtons.OK, MessageBoxIcon.Error);
1194 dev 912
				return;
913
			}
914
 
915
			StartListening(listenPort, resendIp, resendPort);
916
		}
917
 
1199 dev 918
		#endregion windows forms methods
919
 
920
		#region core methods
921
 
922
		private LogLevel ParseLogLevel(string str)
923
		{
924
			if(str == "Important")
925
				return LogLevel.Important;
926
			else if(str == "Info")
927
				return LogLevel.Info;
928
			else
929
				return LogLevel.Debug;
930
		}
931
 
932
		private void LoadFromRegistry()
933
		{
934
			Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
935
				REGISTRY_KEY);
936
 
937
			if(subkey == null) return;
938
 
939
			listenPort           = (int)subkey.GetValue("Listen Port", 0);
940
			resendHost           = (string)subkey.GetValue("Resend Host", "");
941
			resendPort           = (int)subkey.GetValue("Resend Port", 0);
942
			logMessages.Level    = ParseLogLevel((string)subkey.GetValue("Messages Level", ""));
943
			autoExpand           = (int)subkey.GetValue("Auto Expand", 1) == 1;
944
			messagesBox.WordWrap = (int)subkey.GetValue("Word Wrap", 1) == 1;
945
 
946
			object tcpShowModeStr  = (object)subkey.GetValue("Tcp Show Mode", TcpShowMode.ByDirection);
947
			tcpShowMode            = (tcpShowModeStr as string) == "ByDirection"
948
				? TcpShowMode.ByDirection : TcpShowMode.ByTime;
949
 
950
			int winTop  = (int)subkey.GetValue("Window.Top",  -1);
951
			int winLeft = (int)subkey.GetValue("Window.Left", -1);
952
 
953
			if(winTop == -1 || winLeft == -1) {
954
				this.StartPosition = FormStartPosition.WindowsDefaultBounds;
955
			}
956
			else {
957
				this.Top  = winTop;
958
				this.Left = winLeft;
959
				this.ClientSize = new Size(
960
					(int)subkey.GetValue("Window.Width", this.ClientSize.Width),
961
					(int)subkey.GetValue("Window.Hight", this.ClientSize.Height));
1232 dev 962
				this.messageView.Width
1199 dev 963
					= (int)subkey.GetValue("Splitter.Left",   this.messageView.Width);
1232 dev 964
				this.logBox.Height
1199 dev 965
					= (int)subkey.GetValue("Splitter.Bottom", this.logBox.Height);
966
			}
967
		}
968
 
969
		private void LoadRecentItemsFromRegistry()
970
		{
971
			Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
972
				REGISTRY_KEY + @"\" + REGISTRY_RECENT_SUBKEY);
973
 
974
			if(subkey == null) return;
975
 
976
			foreach(string name in subkey.GetValueNames()) {
977
				if(name == "") continue;
978
				AddRecentItem(RecentItem.LoadFromRegistry((string)subkey.GetValue(name, "")));
979
			}
980
		}
981
 
982
		private void SaveToRegistry()
983
		{
984
			Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(
985
				REGISTRY_KEY);
986
 
987
			subkey.SetValue("Listen Port",    listenPort);
988
			subkey.SetValue("Resend Host",    resendHost == null ? "" : resendHost);
989
			subkey.SetValue("Resend Port",    resendPort);
990
			subkey.SetValue("Messages Level", logMessages.Level);
991
			subkey.SetValue("Tcp Show Mode",  tcpShowMode);
992
			subkey.SetValue("Auto Expand",    autoExpand ? 1 : 0);
993
			subkey.SetValue("Word Wrap",      messagesBox.WordWrap ? 1 : 0);
994
 
995
			subkey.SetValue("Window.Top",      this.Top);
996
			subkey.SetValue("Window.Left",     this.Left);
997
			subkey.SetValue("Window.Hight",    this.ClientSize.Height);
998
			subkey.SetValue("Window.Width",    this.ClientSize.Width);
999
			subkey.SetValue("Splitter.Left",   this.messageView.Width);
1000
			subkey.SetValue("Splitter.Bottom", this.logBox.Height);
1001
		}
1002
 
1003
		private void SaveRecentItemsToRegistry()
1004
		{
1005
			Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(
1006
				REGISTRY_KEY + @"\" + REGISTRY_RECENT_SUBKEY);
1007
 
1008
			// load existing from registry
1009
			ArrayList old = new ArrayList();
1010
			foreach(string name in subkey.GetValueNames()) {
1011
				if(name == "") continue;
1012
				old.Add(RecentItem.LoadFromRegistry((string)subkey.GetValue(name, "")));
1013
			}
1014
 
1015
			// merge - for the case another program instance has changed the list
1016
			foreach(RecentItem item in old) {
1017
				int existingIdx = recentItems.IndexOf(item);
1018
				if(existingIdx >= 0)
1019
					((RecentItem)recentItems[existingIdx]).UpdateTimestamp(item);
1020
				else
1021
					recentItems.Add(item);
1022
			}
1023
 
1024
			recentItems.Sort();
1025
			if(recentItems.Count > 0) // take tail
1026
				recentItems = recentItems.GetRange(Math.Max(0, recentItems.Count - RECENT_LENGTH),
1027
					Math.Min(recentItems.Count, RECENT_LENGTH));
1028
 
1029
			int count = 0;
1030
			foreach(RecentItem item in recentItems) {
1031
				subkey.SetValue(string.Format("{0:0000}", count++), item.SaveToRegistry());
1032
			}
1033
		}
1034
 
1194 dev 1035
		private void UpdateMessagesMenuItems()
1036
		{
1037
			switch(logMessages.Level) {
1038
				case LogLevel.Critical:
1039
				case LogLevel.Error:
1040
				case LogLevel.Warning:
1041
				case LogLevel.Important:
1042
					importantMessagesMenuItem.Checked = true;
1043
					infoMessagesMenuItem.Checked      = false;
1044
					allMessagesMenuItem.Checked       = false;
1045
					break;
1046
 
1047
				case LogLevel.Info:
1048
					importantMessagesMenuItem.Checked = false;
1049
					infoMessagesMenuItem.Checked      = true;
1050
					allMessagesMenuItem.Checked       = false;
1051
					break;
1052
 
1053
				case LogLevel.Debug:
1054
					importantMessagesMenuItem.Checked = false;
1055
					infoMessagesMenuItem.Checked      = false;
1056
					allMessagesMenuItem.Checked       = true;
1057
					break;
1058
			}
1059
		}
1060
 
1061
		private void AddRecentItem(int listenPort, string resendHost, int resendPort)
1062
		{
1063
			RecentItem recentItem = new RecentItem(listenPort, resendHost, resendPort);
1064
			recentItem.UpdateTimestamp();
1065
			AddRecentItem(recentItem);
1066
		}
1067
 
1068
		private void AddRecentItem(RecentItem recentItem)
1069
		{
1070
			int existingIdx = recentItems.IndexOf(recentItem);
1071
			if(existingIdx >= 0) {
1239 dev 1072
				this.recentListeningMenu.MenuItems.RemoveAt(recentItems.Count - existingIdx - 1);
1198 dev 1073
				recentItems.RemoveAt(existingIdx);
1194 dev 1074
			}
1075
 
1198 dev 1076
			if(recentItems.Count == 0 && this.recentListeningMenu.MenuItems.Count == 1)
1197 dev 1077
				this.recentListeningMenu.MenuItems.RemoveAt(0);
1078
 
1194 dev 1079
			recentItems.Add(recentItem);
1080
 
1197 dev 1081
			MenuItem menuItem = new MenuItem();
1082
			this.recentListeningMenu.MenuItems.Add(0, menuItem);
1199 dev 1083
			menuItem.Text   = string.Format("&1 {0} to {1}:{2}",
1194 dev 1084
				recentItem.ListenPort, recentItem.ResendHost, recentItem.ResendPort);
1085
			menuItem.Click += new System.EventHandler(recentMenuItem_Click);
1198 dev 1086
 
1087
			// check overflow
1088
			if(recentItems.Count > RECENT_LENGTH) {
1239 dev 1089
				this.recentListeningMenu.MenuItems.RemoveAt(recentItems.Count - 1);
1198 dev 1090
				recentItems.RemoveAt(0);
1091
			}
1199 dev 1092
 
1093
			// update hot keys of old items
1094
			int count = 0;
1095
			foreach(MenuItem item in this.recentListeningMenu.MenuItems) {
1238 dev 1096
				RecentItem ri = (RecentItem)recentItems[recentItems.Count - count - 1];
1097
 
1199 dev 1098
				if(count == 0) {
1099
				}
1100
				else if(count < 10)
1238 dev 1101
					item.Text = string.Format("&{3} {0} to {1}:{2}", ri.ListenPort,
1102
						ri.ResendHost, ri.ResendPort, count + 1);
1199 dev 1103
				else
1238 dev 1104
					item.Text = string.Format("{0} to {1}:{2}", ri.ListenPort,
1105
						ri.ResendHost, ri.ResendPort);
1199 dev 1106
				count++;
1107
			}
1194 dev 1108
		}
1109
 
1199 dev 1110
		private void ClearAll()
1111
		{
1240 dev 1112
			clearing = true;
1092 dev 1113
 
1240 dev 1114
			tcpListener.CancelAll();
1199 dev 1115
 
1116
			treeNodes.Clear();
1239 dev 1117
 
1118
			messageView.BeginUpdate();
1199 dev 1119
			messageView.Nodes.Clear();
1239 dev 1120
			messageView.EndUpdate();
1121
 
1199 dev 1122
			messagesBox.Clear();
1123
			logMessages.Clear();
1240 dev 1124
 
1125
			clearing = false;
1199 dev 1126
		}
1127
 
1092 dev 1128
		private void Start(int listenPort, IPAddress resendHost, int resendPort)
1129
		{
1130
			if(tcpListener != null) tcpListener.StopListening();
1131
 
1132
			tcpListener = new TcpListener(listenPort, resendHost, resendPort);
1133
			tcpListener.Log    += new TcpLogEventHandler(TcpConnectionLog);
1134
			tcpListener.NewTcp += new TcpConnectionEventHandler(AddTcpConnetion);
1135
			tcpListener.StartListening();
1136
		}
1137
 
1199 dev 1138
		private void StartListening(int listenPort, IPAddress resendIp, int resendPort)
1139
		{
1140
			// listen to the port
1141
			try
1142
			{
1143
				Start(listenPort, resendIp, resendPort);
1144
			}
1145
			catch(Exception ex)
1146
			{
1147
				MessageBox.Show("Cannot start listening: " + ex.Message, "TCPproxy",
1148
					MessageBoxButtons.OK, MessageBoxIcon.Error);
1149
				Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1150
				return;
1151
			}
1152
 
1153
			AddRecentItem(listenPort, resendHost, resendPort);
1154
 
1155
			startMenuItem.Enabled = false;
1156
			stopMenuItem.Enabled  = true;
1157
 
1158
			foreach(MenuItem subitem in recentListeningMenu.MenuItems) {
1159
				subitem.Enabled = false;
1160
			}
1161
 
1162
			this.Text = string.Format("{0}: {1} to {2}:{3}",
1163
				defaultCaption, listenPort, resendHost, resendPort);
1164
		}
1165
 
1166
		private void StopListening()
1167
		{
1168
			if(tcpListener != null) tcpListener.StopListening();
1169
 
1170
			startMenuItem.Enabled = true;
1171
			stopMenuItem.Enabled  = false;
1172
 
1173
			if(recentItems.Count > 0) {
1174
				foreach(MenuItem subitem in recentListeningMenu.MenuItems) {
1175
					subitem.Enabled = true;
1176
				}
1177
			}
1178
 
1179
			this.Text = defaultCaption;
1180
		}
1181
 
1288 dev 1182
        private void CloseTcpConnection(TcpConnection tcp)
1092 dev 1183
		{
1184
			if(tcp == null) return;
1185
 
1186
			tcp.Cancel();
1187
		}
1188
 
1189
		private void SaveLog(string fileName)
1190
		{
1191
			StreamWriter writer = new StreamWriter(fileName);
1192
 
1193
			foreach(LogMessage message in logMessages.Messages)
1194
			{
1195
				writer.WriteLine(message);
1196
			}
1197
 
1198
			writer.Close();
1199
		}
1200
 
1201
		private void SaveTcp(string fileName)
1202
		{
1203
			StreamWriter writer = new StreamWriter(fileName);
1204
 
1205
			foreach(TreeNode tcpNode in messageView.Nodes)
1206
			{
1207
				TcpNodeData data = (TcpNodeData)tcpNode.Tag;
1208
				data.WriteLog(writer);
1209
			}
1210
 
1211
			writer.Close();
1212
		}
1213
 
1214
		private void SaveHttp(string fileName)
1215
		{
1216
			StreamWriter writer = new StreamWriter(fileName);
1217
 
1218
			foreach(TreeNode tcpNode in messageView.Nodes)
1219
			{
1220
				foreach(TreeNode httpNode in tcpNode.Nodes)
1221
				{
1222
					HttpNodeData data = (HttpNodeData)httpNode.Tag;
1223
					data.WriteLog(writer);
1224
				}
1225
			}
1226
 
1227
			writer.Close();
1228
		}
1229
 
1230
		private void SaveXml(string fileName)
1231
		{
1232
			StreamWriter writer = new StreamWriter(fileName);
1233
 
1234
			foreach(TreeNode tcpNode in messageView.Nodes)
1235
			{
1236
				foreach(TreeNode httpNode in tcpNode.Nodes)
1237
				{
1238
					foreach(TreeNode xmlNode in httpNode.Nodes)
1239
					{
1240
						XmlNodeData data = (XmlNodeData)xmlNode.Tag;
1241
						data.WriteLog(writer);
1242
					}
1243
				}
1244
			}
1245
 
1246
			writer.Close();
1247
		}
1248
 
1199 dev 1249
		private void SaveBinLog(string fileName)
1250
		{
1251
			FileStream   file   = new FileStream(fileName, FileMode.Create);
1252
			BinaryWriter writer = new BinaryWriter(file);
1253
 
1254
			// header
1255
			writer.Write(Encoding.ASCII.GetBytes(LOG_BIN_HEADER));
1256
			writer.Write(LOG_TYPE_BIN);
1257
 
1258
			// for each tcp connection
1259
			foreach(TreeNode tcpNode in messageView.Nodes)
1260
				((TcpNodeData)tcpNode.Tag).Tcp.WriteBinLog(writer);
1261
 
1262
			// end of stream
1263
			writer.Write((byte)BinLogTypes.None);
1264
 
1265
			writer.Close();
1266
			file.Close();
1267
		}
1268
 
1269
		private void LoadBinLog(string fileName)
1270
		{
1271
			StopListening();
1272
			ClearAll();
1273
 
1232 dev 1274
			FileStream   file   = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
1199 dev 1275
			BinaryReader reader = new BinaryReader(file);
1276
 
1277
			// header
1278
			byte[] bufExpect = Encoding.ASCII.GetBytes(LOG_BIN_HEADER);
1201 dev 1279
			if(file.Length < (bufExpect.Length + 1 /* the type */))
1199 dev 1280
				throw new Exception("The file is too short");
1281
 
1282
			byte[] bufRead = reader.ReadBytes(bufExpect.Length);
1283
			for(int i = 0; i < bufRead.Length; i++)
1284
				if(bufRead[i] != bufExpect[i])
1285
					throw new Exception("Wrong header of the file");
1286
 
1287
			if(reader.ReadByte() != LOG_TYPE_BIN)
1288
				throw new Exception("Unknown log type");
1289
 
1290
			tcpListener = new TcpListener(0, null, 0);
1291
			tcpListener.Log    += new TcpLogEventHandler(TcpConnectionLog);
1292
			tcpListener.NewTcp += new TcpConnectionEventHandler(AddTcpConnetion);
1293
			tcpListener.ReadBinLog(reader); // it will send us usual event
1294
 
1295
			reader.Close();
1296
			file.Close();
1297
		}
1298
 
1092 dev 1299
		#endregion core methods
1300
 
1301
		#region network events handlers
1302
		private void TcpConnectionLog(object sender, TcpLogEventArgs e)
1303
		{
1240 dev 1304
			if(clearing) return;
1305
 
1125 dev 1306
			lock(this)
1307
			{
1308
				TcpConnection tcp = sender as TcpConnection;
1309
				LogMessage message = new LogMessage(tcp, e.Level, e.Message, e.Exception);
1092 dev 1310
 
1125 dev 1311
				try
1312
				{
1313
					this.BeginInvoke(new AddLogMessageHandler(AddLogMessageInternal), new object[] { message } );
1314
				}
1315
				catch(InvalidOperationException ex)
1316
				{
1317
					if(!this.Disposing && !this.IsDisposed)
1318
						Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1319
				}
1092 dev 1320
			}
1321
		}
1322
 
1323
		private void AddTcpConnetion(object sender, TcpConnectionEventArgs e)
1324
		{
1125 dev 1325
			lock(this)
1326
			{
1327
				e.Tcp.Log     += new TcpLogEventHandler(TcpConnectionLog);
1328
				e.Tcp.Update  += new TcpEventHandler(UpdateTcpNode);
1329
				e.Tcp.Close   += new TcpEventHandler(UpdateTcpNode);
1330
				e.Tcp.NewHttp += new TcpHttpEventHandler(AddHttpMessageNode);
1092 dev 1331
 
1125 dev 1332
				try
1333
				{
1334
					this.BeginInvoke(new AddTcpNodeHandler(AddTcpNodeInternal), new object[] { e.Tcp } );
1335
				}
1336
				catch(InvalidOperationException ex)
1337
				{
1338
					if(!this.Disposing && !this.IsDisposed)
1339
						Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1340
				}
1092 dev 1341
			}
1342
		}
1343
 
1344
		private void UpdateTcpNode(object sender, TcpEventArgs e)
1345
		{
1125 dev 1346
			lock(this)
1092 dev 1347
			{
1125 dev 1348
				try
1349
				{
1350
					this.BeginInvoke(new UpdateTcpNodeHandler(UpdateTcpNodeInternal), new object[] { (TcpConnection)sender } );
1351
				}
1352
				catch(InvalidOperationException ex)
1353
				{
1354
					if(!this.Disposing && !this.IsDisposed)
1355
						Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1356
				}
1092 dev 1357
			}
1358
		}
1359
 
1360
		private void AddHttpMessageNode(object sender, TcpHttpEventArgs e)
1361
		{
1125 dev 1362
			lock(this)
1363
			{
1364
				e.Http.Update += new TcpEventHandler(UpdateHttpNode);
1092 dev 1365
 
1125 dev 1366
				try
1367
				{
1368
					this.BeginInvoke(new AddHttpNodeHandler(AddHttpNodeInternal),
1369
						new object[] { (TcpConnection)sender, e.Http } );
1370
				}
1371
				catch(InvalidOperationException ex)
1372
				{
1373
					if(!this.Disposing && !this.IsDisposed)
1374
						Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1375
				}
1092 dev 1376
			}
1377
		}
1378
 
1379
		private void UpdateHttpNode(object sender, TcpEventArgs e)
1380
		{
1125 dev 1381
			lock(this)
1092 dev 1382
			{
1125 dev 1383
				try
1384
				{
1385
					this.BeginInvoke(new UpdateHttpNodeHandler(UpdateHttpNodeInternal), new object[] { (HttpMessage)sender } );
1386
				}
1387
				catch(InvalidOperationException ex)
1388
				{
1389
					if(!this.Disposing && !this.IsDisposed)
1390
						Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1391
				}
1092 dev 1392
			}
1393
		}
1394
 
1395
		#endregion network events handlers
1396
 
1397
		#region handlers for async GUI events
1201 dev 1398
 
1399
		// All handlers are called in main application thread only, no locks needed.
1400
		// Other methods which are not running in the main application thread
1401
		// are not allowed no interact with GUI elemenents.
1402
 
1092 dev 1403
		private delegate void AddLogMessageHandler(LogMessage message);
1404
		private delegate void AddTcpNodeHandler(TcpConnection tcp);
1405
		private delegate void UpdateTcpNodeHandler(TcpConnection tcp);
1406
		private delegate void AddHttpNodeHandler(TcpConnection tcp, HttpMessage http);
1407
		private delegate void UpdateHttpNodeHandler(HttpMessage http);
1408
 
1409
		private void AddLogMessageInternal(LogMessage message)
1410
		{
1411
			logMessages.Add(message);
1412
 
1413
			if(message.Exception != null)
1414
			{
1415
				Console.WriteLine(message.Exception.Message + " (" + message.Exception.GetType().Name
1416
					+ ")\n" + message.Exception.StackTrace);
1417
			}
1418
		}
1419
 
1238 dev 1420
        private string TcpNodeTitle(TcpConnection tcp)
1421
        {
1422
            return tcp.Id + " " + tcp.StartTimestamp.ToString("HH:mm:ss.ffff");
1423
        }
1424
 
1425
        private void AddTcpNodeInternal(TcpConnection tcp)
1092 dev 1426
		{
1238 dev 1427
            TreeNode    treeNode = new TreeNode(TcpNodeTitle(tcp));
1092 dev 1428
			TcpNodeData data     = new TcpNodeData(this, treeNode);
1429
 
1238 dev 1430
			data.Tcp                    = tcp;
1092 dev 1431
			treeNode.Tag                = data;
1232 dev 1432
			treeNode.ImageIndex         = (tcp.LocalState == SocketState.Closed
1199 dev 1433
				&& tcp.RemoteState == SocketState.Closed) ? 2 : 1;
1434
			treeNode.SelectedImageIndex = treeNode.ImageIndex;
1238 dev 1435
			treeNodes[tcp]              = data;
1092 dev 1436
 
1437
			messageView.Nodes.Add(treeNode);
1438
			treeNode.EnsureVisible();
1439
		}
1440
 
1441
		private void UpdateTcpNodeInternal(TcpConnection tcp)
1442
		{
1443
			TcpNodeData data = treeNodes[tcp] as TcpNodeData;
1125 dev 1444
			if(data == null) return; // might be call by Cancel
1092 dev 1445
 
1238 dev 1446
			string title = TcpNodeTitle(tcp);
1092 dev 1447
			if(title != data.Node.Text) data.Node.Text = title;
1448
			if(tcp.LocalState == SocketState.Closed && tcp.RemoteState == SocketState.Closed)
1449
			{
1450
				data.Node.ImageIndex         = 2;
1199 dev 1451
				data.Node.SelectedImageIndex = data.Node.ImageIndex;
1092 dev 1452
			}
1453
 
1454
			if(messageView.SelectedNode == null || data != messageView.SelectedNode.Tag)
1455
				data.ViewExpired = true;  // got update for invisible TCP node, update it later
1456
			else
1457
				data.Show();
1458
		}
1459
 
1238 dev 1460
        private string HttpNodeTitle(HttpMessage http)
1461
        {
1462
            return (http.Request.SoapAction != null ? ("SOAP " + http.Request.SoapAction)
1463
                : (http.Request.Method == null ? "" : http.Request.Method) + " " + (http.Request.Uri == null ? "" : http.Request.Uri));
1464
        }
1465
 
1466
        private void AddHttpNodeInternal(TcpConnection tcp, HttpMessage http)
1092 dev 1467
		{
1238 dev 1468
            TreeNode     treeNode = new TreeNode(HttpNodeTitle(http));
1092 dev 1469
			HttpNodeData data     = new HttpNodeData(this, treeNode);
1470
 
1238 dev 1471
			data.Http       = http;
1472
			treeNode.Tag    = data;
1092 dev 1473
			treeNodes[http] = data;
1474
 
1475
			TcpNodeData tcpData = treeNodes[tcp] as TcpNodeData;
1476
			if(tcpData == null) throw new ArgumentException("No node found for TCP message");
1477
 
1478
			tcpData.Node.Nodes.Add(treeNode);
1479
			if(autoExpand) tcpData.Node.Expand();
1480
			tcpData.Node.EnsureVisible();
1481
		}
1482
 
1483
		private void UpdateHttpNodeInternal(HttpMessage http)
1484
		{
1485
			HttpNodeData httpData = treeNodes[http] as HttpNodeData;
1125 dev 1486
			if(httpData == null) return; // might be call by Cancel
1092 dev 1487
 
1238 dev 1488
            string title = HttpNodeTitle(http);
1092 dev 1489
			if(httpData.Node.Text != title) httpData.Node.Text = title;
1490
 
1234 dev 1491
			if(!httpData.RequestXmlShown && http.Request.Xml != null)
1092 dev 1492
			{
1493
				httpData.RequestXmlShown = true;
1234 dev 1494
				AddXmlNode(httpData.Node, "Request XML", http.Request.Xml);
1092 dev 1495
				if(autoExpand) httpData.Node.Expand();
1496
			}
1497
 
1234 dev 1498
			if(!httpData.ResponseXmlShown && http.Response.Xml != null)
1092 dev 1499
			{
1500
				httpData.ResponseXmlShown = true;
1234 dev 1501
				AddXmlNode(httpData.Node, "Response XML", http.Response.Xml);
1092 dev 1502
				if(autoExpand) httpData.Node.Expand();
1503
			}
1504
 
1505
			// update text view
1506
			if(messageView.SelectedNode == null || httpData != messageView.SelectedNode.Tag)
1507
				httpData.ViewExpired = true;
1508
			else
1509
				httpData.Show();
1510
		}
1511
 
1512
		private void AddXmlNode(TreeNode parent, string title, XmlMessage xml)
1513
		{
1514
			TreeNode    treeNode = new TreeNode(title);
1515
			XmlNodeData data = new XmlNodeData(this, treeNode);
1516
 
1517
			data.Xml       = xml;
1518
			treeNode.Tag   = data;
1519
			treeNodes[xml] = data;
1520
 
1521
			parent.Nodes.Add(treeNode);
1522
		}
1523
 
1524
		#endregion handlers for async GUI events
1525
 
1526
		#region node display classes
1527
		private abstract class TreeNodeData
1528
		{
1529
			protected TreeNode node;
1530
			protected object   viewState;
1531
			protected bool     viewExpired;
1532
			protected MainForm owner;
1533
			protected bool     shown = false;
1534
 
1535
			public TreeNode Node
1536
			{
1537
				get { return node; }
1538
			}
1539
 
1540
			public TreeNodeData(MainForm owner, TreeNode node)
1541
			{
1542
				this.owner = owner;
1543
				this.node  = node;
1544
			}
1545
 
1546
			public bool ViewExpired
1547
			{
1548
				get { return viewExpired; }
1549
				set { viewExpired = value; }
1550
			}
1551
 
1552
			public void SaveViewState()
1553
			{
1554
				viewState = owner.messagesBox.SaveState(false);
1555
			}
1556
 
1557
			protected virtual bool ForceInitView()
1558
			{
1559
				return false;
1560
			}
1561
 
1562
			protected abstract void InitView();
1563
			protected abstract void UpdateView();
1564
 
1565
			public void Show()
1566
			{
1567
				if(!shown || viewState == null || ForceInitView())
1568
				{
1569
					InitView();
1570
					shown = true;
1571
					if(viewState == null) viewState = owner.messagesBox.SaveState(false);
1572
				}
1573
				else
1574
				{
1575
					owner.messagesBox.RestoreState(viewState, true);
1576
					if(viewExpired) UpdateView();
1577
				}
1578
			}
1579
 
1580
			public abstract void WriteLog(StreamWriter writer);
1581
		}
1582
 
1583
		private class TcpNodeData : TreeNodeData
1584
		{
1585
			private TcpConnection tcp;
1586
 
1587
			private TcpShowMode lastShowMode;
1588
			private object      localStateMarker  = null;
1589
			private object      remoteStateMarker = null;
1590
			private object      startMarker       = null;
1591
			private object      localEndMarker    = null;
1592
			private object      remoteEndMarker   = null;
1593
			private object      clientMarker      = null;
1594
			private object      serverMarker      = null;
1595
			private object      sentMarker        = null;
1596
			private object      receivedMarker    = null;
1597
			private object      textMarker1       = null;
1598
			private object      textMarker2       = null;
1599
			private IEnumerator messagesEnum      = null;
1600
 
1601
			public TcpConnection Tcp
1602
			{
1603
				get { return tcp; }
1604
				set { tcp = value; }
1605
			}
1606
 
1607
			public TcpNodeData(MainForm owner, TreeNode node)	: base(owner, node)
1608
			{
1609
			}
1610
 
1611
 
1612
			protected override bool ForceInitView()
1613
			{
1614
				return (lastShowMode != owner.tcpShowMode);
1615
			}
1616
 
1617
			protected override void InitView()
1618
			{
1619
				lastShowMode = owner.tcpShowMode;
1620
 
1621
				try
1622
				{
1623
					owner.messagesBox.BeginUpdate();
1624
 
1625
					lock(tcp)
1626
					{
1627
						owner.messagesBox.Clear();
1628
 
1629
						owner.messagesBox.AppendNewLine();
1630
						owner.messagesBox.AppendText("ID:         ",
1631
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1632
						owner.messagesBox.AppendText(tcp.Id,
1633
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1634
						owner.messagesBox.AppendNewLine();
1635
 
1636
						owner.messagesBox.AppendText("State:      ",
1637
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1638
						localStateMarker = owner.messagesBox.BeginMark();
1639
						owner.messagesBox.AppendText(tcp.LocalState.ToString(),
1640
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1641
						owner.messagesBox.EndMark(localStateMarker);
1642
						owner.messagesBox.AppendText(null,
1643
							Color.DarkRed, Color.Transparent, false, false, 1, 12);
1644
						remoteStateMarker = owner.messagesBox.BeginMark();
1645
						owner.messagesBox.AppendText(tcp.RemoteState.ToString(),
1646
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1647
						owner.messagesBox.EndMark(remoteStateMarker);
1648
						owner.messagesBox.AppendNewLine();
1649
 
1650
						owner.messagesBox.AppendText("Start:      ",
1651
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1652
						startMarker = owner.messagesBox.BeginMark();
1653
						owner.messagesBox.AppendText(tcp.StartTimestamp.ToString("HH:mm:ss.ffff"),
1654
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1655
						owner.messagesBox.EndMark(startMarker);
1656
						owner.messagesBox.AppendNewLine();
1657
						owner.messagesBox.AppendText("Local End:  ",
1658
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1659
						localEndMarker = owner.messagesBox.BeginMark();
1660
						owner.messagesBox.AppendText(tcp.LocalEndTimestamp.ToString("HH:mm:ss.ffff"),
1661
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1662
						owner.messagesBox.EndMark(localEndMarker);
1663
						owner.messagesBox.AppendNewLine();
1664
						owner.messagesBox.AppendText("Remote End: ",
1665
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1666
						remoteEndMarker = owner.messagesBox.BeginMark();
1667
						owner.messagesBox.AppendText(tcp.RemoteEndTimestamp.ToString("HH:mm:ss.ffff"),
1668
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1669
						owner.messagesBox.EndMark(remoteEndMarker);
1670
						owner.messagesBox.AppendNewLine();
1671
 
1672
						owner.messagesBox.AppendText("Client:     ",
1673
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1674
						clientMarker = owner.messagesBox.BeginMark();
1675
						owner.messagesBox.AppendText((tcp.LocalPoint == null) ? "" : tcp.LocalPoint.ToString(),
1676
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1677
						owner.messagesBox.EndMark(clientMarker);
1678
						owner.messagesBox.AppendNewLine();
1679
						owner.messagesBox.AppendText("Server:     ",
1680
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1681
						serverMarker = owner.messagesBox.BeginMark();
1682
						owner.messagesBox.AppendText((tcp.RemotePoint == null) ? "" : tcp.RemotePoint.ToString(),
1683
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1684
						owner.messagesBox.EndMark(serverMarker);
1685
						owner.messagesBox.AppendNewLine();
1686
 
1687
						owner.messagesBox.AppendText("Sent:       ",
1688
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1689
						sentMarker = owner.messagesBox.BeginMark();
1690
						owner.messagesBox.AppendText(tcp.SentBytes.ToString(),
1691
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1692
						owner.messagesBox.EndMark(sentMarker);
1693
						owner.messagesBox.AppendNewLine();
1694
						owner.messagesBox.AppendText("Received:   ",
1695
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1696
						receivedMarker = owner.messagesBox.BeginMark();
1697
						owner.messagesBox.AppendText(tcp.ReceivedBytes.ToString(),
1698
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1699
						owner.messagesBox.EndMark(receivedMarker);
1700
						owner.messagesBox.AppendNewLine();
1701
						owner.messagesBox.AppendNewLine();
1702
 
1703
						messagesEnum = tcp.Messages.GetEnumerator();
1704
 
1705
						textMarker1 = owner.messagesBox.BeginMark();
1706
						owner.messagesBox.EndMark(textMarker1);
1707
 
1708
						owner.messagesBox.AppendNewLine();
1709
						textMarker2 = owner.messagesBox.BeginMark();
1710
						owner.messagesBox.EndMark(textMarker2);
1711
 
1712
						ShowMessages();
1713
					}
1714
				}
1715
				finally
1716
				{
1717
					owner.messagesBox.EndUpdate();
1718
				}
1719
			}
1720
 
1721
			protected override void UpdateView()
1722
			{
1723
				try
1724
				{
1725
					owner.messagesBox.BeginUpdate();
1726
 
1727
					lock(tcp)
1728
					{
1729
						owner.messagesBox.ChangeText(localStateMarker, tcp.LocalState.ToString(),
1730
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1731
						owner.messagesBox.ChangeText(remoteStateMarker, tcp.RemoteState.ToString(),
1732
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1733
 
1734
						owner.messagesBox.ChangeText(startMarker, tcp.StartTimestamp.ToString("HH:mm:ss.ffff"),
1735
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1736
						owner.messagesBox.ChangeText(localEndMarker, tcp.LocalEndTimestamp.ToString("HH:mm:ss.ffff"),
1737
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1738
						owner.messagesBox.ChangeText(remoteEndMarker, tcp.RemoteEndTimestamp.ToString("HH:mm:ss.ffff"),
1739
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1740
 
1741
						owner.messagesBox.ChangeText(clientMarker, (tcp.LocalPoint == null) ? "" : tcp.LocalPoint.ToString(),
1742
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1743
						owner.messagesBox.ChangeText(serverMarker, (tcp.RemotePoint == null) ? "" : tcp.RemotePoint.ToString(),
1744
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1745
 
1746
						owner.messagesBox.ChangeText(sentMarker, tcp.SentBytes.ToString(),
1747
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1748
						owner.messagesBox.ChangeText(receivedMarker, tcp.ReceivedBytes.ToString(),
1749
							Color.DarkRed, Color.LightGray, false, false, 0, 12);
1750
 
1751
						ShowMessages();
1752
					}
1753
				}
1754
				finally
1755
				{
1756
					owner.messagesBox.EndUpdate();
1757
				}
1758
			}
1759
 
1760
			private void ShowMessages()
1761
			{
1762
				while(messagesEnum.MoveNext())
1763
				{
1764
					TcpMessage message = (TcpMessage)messagesEnum.Current;
1765
					object     marker  = (owner.tcpShowMode == TcpShowMode.ByTime
1766
						|| message.Direction == TcpMessageDirection.Local) ? textMarker1 : textMarker2;
1767
 
1768
					if(owner.tcpShowMode == TcpShowMode.ByTime)
1769
					{
1770
						owner.messagesBox.InsertText(marker,
1771
							message.Timestamp.ToString("HH:mm:ss.ffff") + " ("	+ message.Length + ")",
1772
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1773
						owner.messagesBox.InsertNewLine(marker);
1774
					}
1775
 
1776
					string str = Utils.BytesToString(message.Bytes, message.Length);
1777
					ArrayList lines = Utils.SplitLine(str);
1778
					for(int i = 0; i < lines.Count; i++)
1779
					{
1780
						owner.messagesBox.InsertText(marker, (string)lines[i],
1781
							message.Direction == TcpMessageDirection.Local ? Color.Green : Color.Blue,
1782
							Color.LightGray, false, false, 0, 0);
1783
 
1784
						if(owner.tcpShowMode == TcpShowMode.ByTime || i != lines.Count - 1)
1785
							owner.messagesBox.InsertNewLine(marker);
1786
					}
1787
				}
1788
			}
1789
 
1790
			public override void WriteLog(StreamWriter writer)
1791
			{
1792
				writer.WriteLine(
1793
					"Start:      " + tcp.StartTimestamp.ToString("HH:mm:ss.ffff")
1794
					+ "\r\nLocal End:  " + tcp.LocalEndTimestamp.ToString("HH:mm:ss.ffff")
1795
					+ "\r\nRemote End: " + tcp.RemoteEndTimestamp.ToString("HH:mm:ss.ffff")
1796
					+ "\r\nClient:     " + ((tcp.LocalPoint  == null) ? "" : tcp.LocalPoint.ToString())
1797
					+ "\r\nServer:     " + ((tcp.RemotePoint == null) ? "" : tcp.RemotePoint.ToString())
1798
					+ "\r\nSent:       " + tcp.SentBytes
1799
					+ "\r\nReceived:   " + tcp.ReceivedBytes);
1800
 
1801
				foreach(TcpMessage message in tcp.Messages)
1802
				{
1803
					string str = Utils.BytesToString(message.Bytes, message.Length);
1804
					if(!str.EndsWith("\n")) str += "\r\n";
1805
 
1806
					writer.WriteLine();
1807
					if(message.Direction == TcpMessageDirection.Local)
1808
						writer.WriteLine(">>> {0:HH:mm:ss.ffff} >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", message.Timestamp);
1809
					else
1810
						writer.WriteLine("<<< {0:HH:mm:ss.ffff} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", message.Timestamp);
1811
					writer.Write(str);
1812
				}
1813
				writer.WriteLine("===============================================================");
1814
				writer.WriteLine();
1815
			}
1816
		}
1817
 
1818
		private class HttpNodeData : TreeNodeData
1819
		{
1234 dev 1820
			private class MarkerSet
1821
			{
1822
				public object      start;
1823
				public object      method;
1824
				public object      uri;
1825
				public object      version;
1826
				public object      status;
1827
				public object      transferEncoding;
1828
				public object      length;
1829
				public object      contentEncoding;
1830
				public object      contentType;
1831
				public object      charset;
1832
				public object      headers;
1833
				public object      body;
1834
				public IEnumerator headersEnum;
1835
			}
1836
 
1092 dev 1837
			private HttpMessage http;
1838
			private bool        requestXmlShown  = false;
1839
			private bool        responseXmlShown = false;
1840
 
1234 dev 1841
			private object      stateMarker      = null;
1842
			private MarkerSet   requestMarkers   = new MarkerSet();
1843
			private MarkerSet   responseMarkers  = new MarkerSet();
1092 dev 1844
 
1845
			public HttpMessage Http
1846
			{
1847
				get { return http; }
1848
				set { http = value; }
1849
			}
1850
 
1851
			public bool RequestXmlShown
1852
			{
1853
				get { return requestXmlShown; }
1854
				set { requestXmlShown = value; }
1855
			}
1856
 
1857
			public bool ResponseXmlShown
1858
			{
1859
				get { return responseXmlShown; }
1860
				set { responseXmlShown = value; }
1861
			}
1862
 
1863
			public HttpNodeData(MainForm owner, TreeNode node) : base(owner, node)
1864
			{
1865
			}
1866
 
1233 dev 1867
			private string EncodingToString(HttpTransferEncoding encoding)
1092 dev 1868
			{
1869
				switch(encoding)
1870
				{
1233 dev 1871
					case HttpTransferEncoding.None:     return "none";
1872
					case HttpTransferEncoding.Identity: return "identity";
1873
					case HttpTransferEncoding.Chunked:  return "chunked";
1874
					case HttpTransferEncoding.Gzip:     return "gzip";
1875
					case HttpTransferEncoding.Compress: return "compress";
1876
					case HttpTransferEncoding.Deflate:  return "deflate";
1877
					default:                            return "<unknown>";
1092 dev 1878
				}
1879
			}
1880
 
1233 dev 1881
			private string EncodingToString(HttpContentEncoding encoding)
1882
			{
1883
				switch(encoding)
1884
				{
1885
					case HttpContentEncoding.None:     return "none";
1886
					case HttpContentEncoding.Identity: return "identity";
1887
					case HttpContentEncoding.Gzip:     return "gzip";
1888
					case HttpContentEncoding.Compress: return "compress";
1889
					case HttpContentEncoding.Deflate:  return "deflate";
1890
					default:                           return "<unknown>";
1891
				}
1892
			}
1893
 
1234 dev 1894
			private string VersionToString(HttpVersion version)
1092 dev 1895
			{
1234 dev 1896
				switch(version)
1092 dev 1897
				{
1234 dev 1898
					case HttpVersion.V0_9: return "HTTP/0.9";
1899
					case HttpVersion.V1_0: return "HTTP/1.0";
1900
					default:               return "HTTP/1.1";
1901
				}
1902
			}
1092 dev 1903
 
1234 dev 1904
			private void InitHttpHalfView(HttpHalfMessage half, MarkerSet markers, string title)
1905
			{
1906
				string padding = "";
1092 dev 1907
 
1234 dev 1908
				owner.messagesBox.AppendText(title + " Start:             " + padding,
1909
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1910
				markers.start = owner.messagesBox.BeginMark();
1911
				owner.messagesBox.AppendText(half.StartTimestamp == DateTime.MinValue
1912
					? "<unknown>" : half.StartTimestamp.ToString("HH:mm:ss.ffff"),
1913
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1914
				owner.messagesBox.EndMark(markers.start);
1915
				owner.messagesBox.AppendNewLine();
1125 dev 1916
 
1234 dev 1917
				if(half.IsRequest)
1918
				{
1919
					owner.messagesBox.AppendText(title + " Method:            " + padding,
1920
						Color.DarkRed, Color.Transparent, false, false, 0, 0);
1921
					markers.method = owner.messagesBox.BeginMark();
1922
					owner.messagesBox.AppendText((half as HttpRequest).Method,
1923
						Color.DarkRed, Color.LightGray, false, false, 0, 27);
1924
					owner.messagesBox.EndMark(markers.method);
1925
					owner.messagesBox.AppendNewLine();
1092 dev 1926
 
1234 dev 1927
					owner.messagesBox.AppendText(title + " URI:               " + padding,
1928
						Color.DarkRed, Color.Transparent, false, false, 0, 0);
1929
					markers.uri = owner.messagesBox.BeginMark();
1930
					owner.messagesBox.AppendText((half as HttpRequest).Uri,
1931
						Color.DarkRed, Color.LightGray, false, false, 0, 27);
1932
					owner.messagesBox.EndMark(markers.uri);
1933
					owner.messagesBox.AppendNewLine();
1934
				}
1935
				else 
1936
				{
1937
					owner.messagesBox.AppendText(title + " Status:            " + padding,
1938
						Color.DarkRed, Color.Transparent, false, false, 0, 0);
1939
					markers.status = owner.messagesBox.BeginMark();
1940
					owner.messagesBox.AppendText((half as HttpResponse).StatusCode 
1941
						+ " " + (half as HttpResponse).StatusMessage,
1942
						Color.DarkRed, Color.LightGray, false, false, 0, 27);
1943
					owner.messagesBox.EndMark(markers.status);
1944
					owner.messagesBox.AppendNewLine();
1945
				}
1092 dev 1946
 
1234 dev 1947
				owner.messagesBox.AppendText(title + " Version:           " + padding,
1948
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1949
				markers.version = owner.messagesBox.BeginMark();
1950
				owner.messagesBox.AppendText(VersionToString(half.Version),
1951
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1952
				owner.messagesBox.EndMark(markers.version);
1953
				owner.messagesBox.AppendNewLine();
1092 dev 1954
 
1234 dev 1955
				owner.messagesBox.AppendText(title + " Transfer Encoding: " + padding,
1956
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1957
				markers.transferEncoding = owner.messagesBox.BeginMark();
1958
				owner.messagesBox.AppendText(EncodingToString(half.TransferEncoding),
1959
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1960
				owner.messagesBox.EndMark(markers.transferEncoding);
1961
				owner.messagesBox.AppendNewLine();
1233 dev 1962
 
1234 dev 1963
				owner.messagesBox.AppendText(title + " Content Length:    " + padding,
1964
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1965
				markers.length = owner.messagesBox.BeginMark();
1966
				owner.messagesBox.AppendText(half.Length < 0 ? "<unknown>" : half.Length.ToString(),
1967
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1968
				owner.messagesBox.EndMark(markers.length);
1969
				owner.messagesBox.AppendNewLine();
1092 dev 1970
 
1234 dev 1971
				owner.messagesBox.AppendText(title + " Content Encoding:  " + padding,
1972
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1973
				markers.contentEncoding = owner.messagesBox.BeginMark();
1974
				owner.messagesBox.AppendText(EncodingToString(half.ContentEncoding),
1975
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1976
				owner.messagesBox.EndMark(markers.contentEncoding);
1977
				owner.messagesBox.AppendNewLine();
1092 dev 1978
 
1234 dev 1979
				owner.messagesBox.AppendText(title + " Content Type:      " + padding,
1980
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1981
				markers.contentType = owner.messagesBox.BeginMark();
1982
				owner.messagesBox.AppendText(half.ContentType == null ? "<unknown>"
1983
					: half.ContentType + "/" + half.ContentSubtype,
1984
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1985
				owner.messagesBox.EndMark(markers.contentType);
1986
				owner.messagesBox.AppendNewLine();
1092 dev 1987
 
1234 dev 1988
				owner.messagesBox.AppendText(title + " Content Charset:   " + padding,
1989
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1990
				markers.charset = owner.messagesBox.BeginMark();
1991
				owner.messagesBox.AppendText(half.Charset == null ? "<unknown>" : half.Charset,
1992
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1993
				owner.messagesBox.EndMark(markers.charset);
1994
				owner.messagesBox.AppendNewLine();
1092 dev 1995
 
1234 dev 1996
				owner.messagesBox.AppendText(title + " Headers:",
1997
					Color.DarkRed, Color.Transparent, false, false, 0, 0);
1998
				owner.messagesBox.AppendNewLine();
1999
				markers.headers = owner.messagesBox.BeginMark();
2000
				owner.messagesBox.EndMark(markers.headers);
1092 dev 2001
 
1234 dev 2002
				markers.headersEnum = half.Headers.GetEnumerator();
2003
				ShowHeaders(markers.headersEnum, markers.headers);
2004
			}
1092 dev 2005
 
1234 dev 2006
			private void UpdateHttpHalfView(HttpHalfMessage half, MarkerSet markers)
2007
			{
2008
				if(half.IsRequest)
2009
				{
2010
					owner.messagesBox.ChangeText(markers.method, (half as HttpRequest).Method,
2011
						Color.DarkRed, Color.LightGray, false, false, 0, 27);
2012
					owner.messagesBox.ChangeText(markers.uri, (half as HttpRequest).Uri,
2013
						Color.DarkRed, Color.LightGray, false, false, 0, 27);
2014
				}
2015
				else
2016
				{
2017
					owner.messagesBox.ChangeText(markers.status, (half as HttpResponse).StatusCode + " " + (half as HttpResponse).StatusMessage,
2018
						Color.DarkRed, Color.LightGray, false, false, 0, 27);
2019
				}
1125 dev 2020
 
1234 dev 2021
				owner.messagesBox.ChangeText(markers.version, VersionToString(half.Version),
2022
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
2023
				owner.messagesBox.ChangeText(markers.transferEncoding, EncodingToString(half.TransferEncoding),
2024
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
2025
				owner.messagesBox.ChangeText(markers.length, half.Length < 0
2026
					? "<unknown>" : half.Length.ToString(),
2027
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
2028
				owner.messagesBox.ChangeText(markers.contentEncoding, EncodingToString(half.ContentEncoding),
2029
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
2030
				owner.messagesBox.ChangeText(markers.contentType, half.ContentType == null ? "<unknown>"
2031
					: half.ContentType + "/" + half.ContentSubtype,
2032
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
2033
				owner.messagesBox.ChangeText(markers.charset, half.Charset == null
2034
					? "<unknown>" : half.Charset,
2035
					Color.DarkRed, Color.LightGray, false, false, 0, 27);
1092 dev 2036
 
1234 dev 2037
				ShowHeaders(markers.headersEnum, markers.headers);
2038
			}
1092 dev 2039
 
1234 dev 2040
			protected override void InitView()
2041
			{
2042
				try
2043
				{
2044
					lock(http)
2045
					{
2046
						owner.messagesBox.Clear();
1233 dev 2047
 
1234 dev 2048
						// state
1092 dev 2049
						owner.messagesBox.AppendNewLine();
1234 dev 2050
						owner.messagesBox.AppendText("Complete:                   ",
1092 dev 2051
							Color.DarkRed, Color.Transparent, false, false, 0, 0);
1234 dev 2052
						stateMarker = owner.messagesBox.BeginMark();
2053
						owner.messagesBox.AppendText(http.Request.Complete && http.Response.Complete ? "YES" : "NO",
1092 dev 2054
							Color.DarkRed, Color.LightGray, false, false, 0, 27);
1234 dev 2055
						owner.messagesBox.EndMark(stateMarker);
1092 dev 2056
						owner.messagesBox.AppendNewLine();
2057
						owner.messagesBox.AppendNewLine();
2058
 
1234 dev 2059
						// general info
2060
						InitHttpHalfView(http.Request,  requestMarkers,  "Request");
2061
						InitHttpHalfView(http.Response, responseMarkers, "Response");
1092 dev 2062
 
1234 dev 2063
						// bodies
1092 dev 2064
						owner.messagesBox.AppendNewLine();
1234 dev 2065
						requestMarkers.body = owner.messagesBox.BeginMark();
2066
						owner.messagesBox.EndMark(requestMarkers.body);
2067
						ShowBody(requestMarkers, http.Request, Color.Green);
1092 dev 2068
 
2069
						owner.messagesBox.AppendNewLine();
1234 dev 2070
						responseMarkers.body = owner.messagesBox.BeginMark();
2071
						owner.messagesBox.EndMark(responseMarkers.body);
2072
						ShowBody(responseMarkers, http.Response, Color.Blue);
1092 dev 2073
					}
2074
				}
2075
				finally
2076
				{
2077
					owner.messagesBox.EndUpdate();
2078
				}
2079
			}
2080
 
2081
			protected override void UpdateView()
2082
			{
2083
				try
2084
				{
2085
					owner.messagesBox.BeginUpdate();
2086
 
2087
					lock(http)
2088
					{
1234 dev 2089
						// state
2090
						owner.messagesBox.ChangeText(stateMarker, http.Request.Complete && http.Response.Complete ? "YES" : "NO",
1092 dev 2091
							Color.DarkRed, Color.LightGray, false, false, 0, 27);
2092
 
1234 dev 2093
						// general info
2094
						UpdateHttpHalfView(http.Request,  requestMarkers);
2095
						UpdateHttpHalfView(http.Response, responseMarkers);
1092 dev 2096
 
1234 dev 2097
						// bodies
2098
						owner.messagesBox.DeleteText(requestMarkers.body);
2099
						ShowBody(requestMarkers, http.Request, Color.Green);
2100
						owner.messagesBox.DeleteText(responseMarkers.body);
2101
						ShowBody(responseMarkers, http.Response, Color.Blue);
1092 dev 2102
					}
2103
				}
2104
				finally
2105
				{
2106
					owner.messagesBox.EndUpdate();
2107
				}
2108
			}
2109
 
2110
			private void ShowHeaders(IEnumerator headers, object marker)
2111
			{
2112
				while(headers.MoveNext())
2113
				{
2114
					HttpHeader h = (HttpHeader)headers.Current;
2115
 
2116
					bool first = true;
2117
					foreach(string val in h.Values)
2118
					{
2119
						if(first)
2120
						{
2121
							owner.messagesBox.InsertText(marker, h.Name + ":",
2122
								Color.DarkRed, Color.Transparent, false, false, 4, 4);
2123
							owner.messagesBox.InsertText(marker, null,
2124
								Color.DarkRed, Color.Transparent, false, false, 6 - 4 - 1, 4);
2125
							first = false;
2126
						}
2127
						else
2128
						{
2129
							owner.messagesBox.InsertText(marker, null,
2130
								Color.DarkRed, Color.Transparent, false, false, 6 + h.Name.Length, 6 + h.Name.Length);
2131
						}
2132
						owner.messagesBox.InsertText(marker, val,
2133
							Color.DarkRed, Color.LightGray, false, false, 0, 6 + h.Name.Length);
2134
						owner.messagesBox.InsertNewLine(marker);
2135
					}
2136
				}
2137
			}
2138
 
1234 dev 2139
			private void ShowBody(MarkerSet markers, HttpHalfMessage half, Color color)
1092 dev 2140
			{
1234 dev 2141
				if(half.Text != null)
1092 dev 2142
				{
1234 dev 2143
					ArrayList lines = Utils.SplitLine(half.Text);
1092 dev 2144
					for(int i = 0; i < lines.Count; i++)
2145
					{
1234 dev 2146
						owner.messagesBox.InsertText(markers.body, (string)lines[i], color, Color.LightGray, false, false, 0, 0);
2147
						owner.messagesBox.InsertNewLine(markers.body);
1092 dev 2148
					}
2149
				}
1234 dev 2150
				else if(half.Body != null)
1092 dev 2151
				{
1234 dev 2152
					ArrayList lines = Utils.SplitLine(Utils.BytesToString(half.Body, half.Length));
1092 dev 2153
					for(int i = 0; i < lines.Count; i++)
2154
					{
1234 dev 2155
						owner.messagesBox.InsertText(markers.body, (string)lines[i], color, Color.LightGray, false, false, 0, 0);
2156
						owner.messagesBox.InsertNewLine(markers.body);
1092 dev 2157
					}
2158
				}
2159
			}
2160
 
2161
			public override void WriteLog(StreamWriter writer)
2162
			{
2163
				// request info
2164
				writer.WriteLine(
1234 dev 2165
					"Complete:                   " + (http.Request.Complete && http.Response.Complete ? "YES" : "NO") + "\r\n"
2166
					+ "\r\nRequest Method:             " + http.Request.Method
2167
					+ "\r\nRequest URI:                " + http.Request.Uri
2168
					+ "\r\nRequest Version:            " + (http.Request.Version == HttpVersion.V0_9 ? "HTTP/0.9"
2169
						: http.Request.Version == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1")
2170
					+ "\r\nRequest Transfer Encoding:  " + EncodingToString(http.Request.TransferEncoding)
2171
					+ "\r\nRequest Content Length:     " + (http.Request.Length < 0 ? "<unknown>" : http.Request.Length.ToString())
2172
					+ "\r\nRequest Content Encoding:   " + EncodingToString(http.Request.ContentEncoding)
2173
					+ "\r\nRequest Content Type:       " + (http.Request.ContentType == null ? "<unknown>"
2174
						: http.Request.ContentType + "/" + http.Request.ContentSubtype)
2175
					+ "\r\nRequest Content Charset:    " + (http.Request.Charset == null ? "<unknown>" : http.Request.Charset)
1092 dev 2176
					+ "\r\nRequest Headers:");
2177
 
1234 dev 2178
				foreach(HttpHeader h in http.Request.Headers)
1092 dev 2179
				{
2180
					int indent = 0;
2181
					foreach(string val in h.Values)
2182
					{
2183
						if(indent == 0)
2184
						{
2185
							writer.WriteLine("    {0}: {1}", h.Name, val);
2186
							indent = 6 + h.Name.Length;
2187
						}
2188
						else
2189
						{
2190
							writer.WriteLine("{0," + indent + "}{1}", " ", val);
2191
						}
2192
					}
2193
				}
2194
 
2195
				// response info
2196
				writer.WriteLine(
1234 dev 2197
					"\r\nResponse Version:           " + (http.Response.Version == HttpVersion.V0_9
2198
						? "HTTP/0.9" : http.Response.Version == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1")
2199
					+ "\r\nResponse Status:            " + http.Response.StatusCode + " " + http.Response.StatusMessage
2200
					+ "\r\nResponse Transfer Encoding: " + EncodingToString(http.Response.TransferEncoding)
2201
					+ "\r\nResponse Content Length:    " + (http.Response.Length < 0
2202
						? "<unknown>" : http.Response.Length.ToString())
2203
					+ "\r\nResponse Content Encoding:  " + EncodingToString(http.Response.ContentEncoding)
2204
					+ "\r\nResponse Content Type:      " + (http.Response.ContentType == null ? "<unknown>"
2205
						: http.Response.ContentType + "/" + http.Response.ContentSubtype)
2206
					+ "\r\nResponse Content Charset:   " + (http.Response.Charset == null ? "<unknown>" : http.Response.Charset)
1092 dev 2207
					+ "\r\nResponse Headers:");
2208
 
1234 dev 2209
				foreach(HttpHeader h in http.Response.Headers)
1092 dev 2210
				{
2211
					int indent = 0;
2212
					foreach(string val in h.Values)
2213
					{
2214
						if(indent == 0)
2215
						{
2216
							writer.WriteLine("    {0}: {1}", h.Name, val);
2217
							indent = 6 + h.Name.Length;
2218
						}
2219
						else
2220
						{
2221
							writer.WriteLine("{0," + indent + "}{1}", " ", val);
2222
						}
2223
					}
2224
				}
2225
				writer.WriteLine();
2226
 
2227
				// request body
1234 dev 2228
				if(http.Request.Text != null)
1092 dev 2229
				{
1234 dev 2230
					writer.WriteLine(http.Request.Text);
1092 dev 2231
				}
1234 dev 2232
				else if(http.Request.Body != null)
1092 dev 2233
				{
1234 dev 2234
					writer.WriteLine(Utils.BytesToString(http.Request.Body, http.Request.Length));
1092 dev 2235
				}
2236
 
2237
				// response body
1234 dev 2238
				if(http.Response.Text != null)
1092 dev 2239
				{
1234 dev 2240
					writer.WriteLine(http.Response.Text);
1092 dev 2241
				}
1234 dev 2242
				else if(http.Response.Body != null)
1092 dev 2243
				{
1234 dev 2244
					writer.WriteLine(Utils.BytesToString(http.Response.Body, http.Response.Length));
1092 dev 2245
				}
2246
 
2247
				writer.WriteLine("===============================================================");
2248
				writer.WriteLine();
2249
			}
2250
		}
2251
 
2252
		private class XmlNodeData : TreeNodeData
2253
		{
2254
			private XmlMessage xml;
2255
 
2256
			public XmlMessage Xml
2257
			{
2258
				get { return xml; }
2259
				set { xml = value; }
2260
			}
2261
 
2262
			public XmlNodeData(MainForm owner, TreeNode node) : base(owner, node)
2263
			{
2264
			}
2265
 
2266
			protected override void InitView()
2267
			{
2268
				try
2269
				{
2270
					// update main screen if necessary
2271
					owner.messagesBox.BeginUpdate();
2272
 
2273
					lock(xml)
2274
					{
2275
						owner.messagesBox.Clear();
2276
						if(xml.ParseException != null)
2277
						{
2278
							owner.messagesBox.AppendText("Cannot parse XML:",
2279
								Color.Red, Color.Transparent, false, false, 0, 0);
2280
							owner.messagesBox.AppendNewLine();
2281
							owner.messagesBox.AppendText(xml.ParseException.Message,
2282
								Color.Red, Color.Transparent, false, false, 2, 2);
2283
							owner.messagesBox.AppendNewLine();
2284
						}
2285
						else if(xml.Xml != null)
2286
						{
2287
							ShowXmlNode(xml.Xml, 0);
2288
						}
2289
					}
2290
				}
2291
				finally
2292
				{
2293
					owner.messagesBox.EndUpdate();
2294
				}
2295
			}
2296
 
2297
			protected override void UpdateView()
2298
			{
2299
			}
2300
 
2301
			private void ShowXmlNode(XmlNode node, int indent)
2302
			{
2303
				if(node.NodeType == XmlNodeType.Document)
2304
				{
2305
					foreach(XmlNode subnode in node.ChildNodes)
2306
					{
2307
						ShowXmlNode(subnode, indent);
2308
					}
2309
				}
2310
				else if(node.NodeType == XmlNodeType.XmlDeclaration)
2311
				{
2312
					owner.messagesBox.AppendText("<?" + node.Name + " " + node.Value + " ?>",
2313
						Color.Blue, Color.Transparent, false, false, indent, indent+2);
2314
					owner.messagesBox.AppendNewLine();
2315
				}
2316
				else if(node.NodeType == XmlNodeType.Comment)
2317
				{
2318
					owner.messagesBox.AppendText("<!--", Color.Gray, Color.Transparent, false, false, indent, indent + 2);
2319
					ShowNormalizedXmlValue(node.Value, Color.Gray, Color.Thistle, false, false, indent);
2320
					owner.messagesBox.AppendText("-->", Color.Gray, Color.Transparent, false, false, 0, indent + 2);
2321
					owner.messagesBox.AppendNewLine();
2322
				}
2323
				else if(node.NodeType == XmlNodeType.Element)
2324
				{
2325
					owner.messagesBox.AppendText("<", Color.Blue, Color.Transparent, false, false, indent, indent + 2);
2326
					owner.messagesBox.AppendText(node.Name, Color.DarkRed, Color.Transparent, false, false, 0, indent + 2);
2327
 
2328
					foreach(XmlAttribute attr in node.Attributes)
2329
					{
2330
						bool xmlAttr = attr.Name.StartsWith("xml");
2331
						owner.messagesBox.AppendText(attr.Name, xmlAttr ? Color.Red : Color.DarkRed, Color.Transparent, false, false, 1, indent + 2);
2332
						owner.messagesBox.AppendText("=\"", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
2333
						owner.messagesBox.AppendText(attr.Value, xmlAttr ? Color.Red : Color.DarkRed, Color.Transparent, false, false, 0, indent + 2);
2334
						owner.messagesBox.AppendText("\"", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
2335
					}
2336
 
2337
					if(!node.HasChildNodes)
2338
					{
2339
						owner.messagesBox.AppendText(" />", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
2340
						owner.messagesBox.AppendNewLine();
2341
					}
2342
					else
2343
					{
2344
						owner.messagesBox.AppendText(">", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
2345
 
2346
						bool elementExists = false;
2347
						bool lastText      = true;
2348
						foreach(XmlNode subnode in node.ChildNodes)
2349
						{
2350
							if(subnode.NodeType == XmlNodeType.Text)
2351
							{
2352
								if(elementExists) owner.messagesBox.AppendNewLine();
2353
								ShowNormalizedXmlValue(subnode.Value, Color.Black, Color.LightGray, false, false, indent);
2354
								lastText = true;
2355
							}
2356
							else
2357
							{
2358
								if(lastText) owner.messagesBox.AppendNewLine();
2359
								ShowXmlNode(subnode, indent + 2);
2360
								elementExists = true;
2361
								lastText      = false;
2362
							}
2363
						}
2364
 
2365
						if(elementExists) owner.messagesBox.AppendText(null, Color.Black, Color.Transparent, false, false, indent, indent + 2);
2366
						owner.messagesBox.AppendText("</", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
2367
						owner.messagesBox.AppendText(node.Name, Color.DarkRed, Color.Transparent, false, false, 0, indent + 2);
2368
						owner.messagesBox.AppendText(">", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
2369
						owner.messagesBox.AppendNewLine();
2370
					}
2371
				}
2372
			}
2373
 
2374
			private void ShowNormalizedXmlValue(string s, Color color, Color backColor, bool italic, bool bold, int indent)
2375
			{
2376
				int begin;
2377
				int end;
2378
 
2379
				bool newLineFound = false;
2380
				foreach(char c in s)
2381
				{
2382
					if(c == '\n')
2383
					{
2384
						newLineFound = true;
2385
						break;
2386
					}
2387
				}
2388
 
2389
				if(newLineFound)
2390
				{
2391
					owner.messagesBox.AppendNewLine();
2392
					owner.messagesBox.AppendText(null, color, Color.Transparent, italic, bold, indent, indent);
2393
					owner.messagesBox.AppendText(null, color, backColor, italic, bold, 2, 2);
2394
				}
2395
 
2396
				// trim
2397
				for(begin = 0; begin < s.Length; begin++)
2398
				{
2399
					char c = s[begin];
2400
					if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
2401
				}
2402
				for(end = s.Length-1; end >= 0; end--)
2403
				{
2404
					char c = s[end];
2405
					if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
2406
				}
2407
 
2408
				StringBuilder b = new StringBuilder(s.Length);
2409
				for(int i = begin; i <= end; i++)
2410
				{
2411
					char c = s[i];
2412
 
2413
					switch(c)
2414
					{
2415
						case '\n':
2416
							if(b.Length > 0)
2417
							{
2418
								owner.messagesBox.AppendText(b.ToString(), color, backColor, italic, bold, 0, indent + 2);
2419
								b.Length = 0;
2420
							}
2421
 
2422
							owner.messagesBox.AppendNewLine();
2423
							owner.messagesBox.AppendText(null, color, Color.Transparent, italic, bold, indent, indent);
2424
							owner.messagesBox.AppendText(null, color, backColor, italic, bold, 2, 2);
2425
							break;
2426
 
2427
						case '\r':
2428
							break;
2429
 
2430
						case '\t':
2431
							b.Append("  ");
2432
							break;
2433
 
2434
						default:
2435
							b.Append(c);
2436
							break;
2437
					}
2438
				}
2439
 
2440
				if(b.Length > 0)
2441
					owner.messagesBox.AppendText(b.ToString(), color, backColor, italic, bold, 0, indent + 2);
2442
 
2443
				if(newLineFound)
2444
				{
2445
					owner.messagesBox.AppendNewLine();
2446
					owner.messagesBox.AppendText(null, color, Color.Transparent, italic, bold, indent, indent + 2);
2447
				}
2448
			}
2449
 
2450
			public override void WriteLog(StreamWriter writer)
2451
			{
2452
				WriteXmlNode(writer, xml.Xml, "");
2453
				writer.WriteLine("===============================================================");
2454
				writer.WriteLine();
2455
			}
2456
 
2457
			private void WriteXmlNode(StreamWriter writer, XmlNode node, string indent)
2458
			{
2459
				if(node.NodeType == XmlNodeType.Document)
2460
				{
2461
					foreach(XmlNode subnode in node.ChildNodes)
2462
					{
2463
						WriteXmlNode(writer, subnode, indent);
2464
					}
2465
				}
2466
				else if(node.NodeType == XmlNodeType.XmlDeclaration)
2467
				{
2468
					writer.WriteLine(indent + "<?" + node.Name + " " + node.Value + " ?>");
2469
				}
2470
				else if(node.NodeType == XmlNodeType.Comment)
2471
				{
2472
					writer.Write(indent + "<!--");
2473
					WriteNormalizedXmlValue(writer, node.Value, indent);
2474
					writer.WriteLine("-->");
2475
				}
2476
				else if(node.NodeType == XmlNodeType.Element)
2477
				{
2478
					writer.Write(indent + "<" + node.Name);
2479
 
2480
					foreach(XmlAttribute attr in node.Attributes)
2481
					{
2482
						bool xmlAttr = attr.Name.StartsWith("xml");
2483
						writer.Write(" " + attr.Name + "=\"" + attr.Value + "\"");
2484
					}
2485
 
2486
					if(!node.HasChildNodes)
2487
					{
2488
						writer.WriteLine(" />");
2489
					}
2490
					else
2491
					{
2492
						writer.Write(">");
2493
 
2494
						bool elementExists = false;
2495
						bool lastText      = true;
2496
						foreach(XmlNode subnode in node.ChildNodes)
2497
						{
2498
							if(subnode.NodeType == XmlNodeType.Text)
2499
							{
2500
								if(elementExists) writer.WriteLine();
2501
								WriteNormalizedXmlValue(writer, subnode.Value, indent);
2502
								lastText = true;
2503
							}
2504
							else
2505
							{
2506
								if(lastText) writer.WriteLine();
2507
								WriteXmlNode(writer, subnode, indent + "  ");
2508
								elementExists = true;
2509
								lastText      = false;
2510
							}
2511
						}
2512
 
2513
						if(elementExists) writer.Write(indent);
2514
						writer.WriteLine("</" + node.Name + ">");
2515
					}
2516
				}
2517
			}
2518
 
2519
			private void WriteNormalizedXmlValue(StreamWriter writer, string s, string indent)
2520
			{
2521
				int begin;
2522
				int end;
2523
 
2524
				bool newLineFound = false;
2525
				foreach(char c in s)
2526
				{
2527
					if(c == '\n')
2528
					{
2529
						newLineFound = true;
2530
						break;
2531
					}
2532
				}
2533
 
2534
				if(newLineFound)
2535
				{
2536
					writer.WriteLine();
2537
					writer.Write(indent + "  ");
2538
				}
2539
 
2540
				// trim
2541
				for(begin = 0; begin < s.Length; begin++)
2542
				{
2543
					char c = s[begin];
2544
					if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
2545
				}
2546
				for(end = s.Length-1; end >= 0; end--)
2547
				{
2548
					char c = s[end];
2549
					if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
2550
				}
2551
 
2552
				StringBuilder b = new StringBuilder(s.Length);
2553
				for(int i = begin; i <= end; i++)
2554
				{
2555
					char c = s[i];
2556
 
2557
					switch(c)
2558
					{
2559
						case '\n':
2560
							if(b.Length > 0)
2561
							{
2562
								writer.Write(b.ToString());
2563
								b.Length = 0;
2564
							}
2565
 
2566
							writer.WriteLine();
2567
							writer.Write(indent + "  ");
2568
							break;
2569
 
2570
						case '\r':
2571
							break;
2572
 
2573
						case '\t':
2574
							b.Append("  ");
2575
							break;
2576
 
2577
						case '&':
2578
							b.Append("&amp;");
2579
							break;
2580
 
2581
						case '<':
2582
							b.Append("&lt;");
2583
							break;
2584
 
2585
						case '>':
2586
							b.Append("&gt;");
2587
							break;
2588
 
2589
						default:
2590
							b.Append(c);
2591
							break;
2592
					}
2593
				}
2594
 
2595
				if(b.Length > 0)
2596
					writer.Write(b.ToString());
2597
 
2598
				if(newLineFound)
2599
				{
2600
					writer.WriteLine();
2601
					writer.Write(indent + "  ");
2602
				}
2603
			}
2604
		}
2605
 
2606
		#endregion node display classes
2607
 
2608
		#region other classes
2609
		private abstract class Utils
2610
		{
2611
			public static string BytesToString(byte[] bytes, int length)
2612
			{
2613
				if(bytes == null) return null;
2614
 
2615
				char[]  chars   = new char[length + 1];
2616
				Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
2617
				int     charLen = decoder.GetChars(bytes, 0, length, chars, 0);
2618
 
2619
				for(int i = 0; i < charLen; i++)
2620
				{
2621
					char c = chars[i];
2622
					if(c != '\n' && c != '\r' && Char.IsControl(c)) chars[i] = '.';
2623
				}
2624
 
2625
				return (new System.String(chars)).Substring(0, charLen);
2626
			}
2627
 
2628
			public static ArrayList SplitLine(string line)
2629
			{
2630
				if(line == null) return null;
2631
 
2632
				ArrayList    res = new ArrayList();
2633
				StringBuilder b  = new StringBuilder(200);
2634
 
2635
				foreach(char c in line)
2636
				{
2637
					switch(c)
2638
					{
2639
						case '\r':
2640
							break;
2641
 
2642
						case '\n':
2643
							res.Add(b.ToString());
2644
							b.Length = 0;
2645
							break;
2646
 
2647
						default:
2648
							b.Append(c);
2649
							break;
2650
					}
2651
				}
2652
 
2653
				res.Add(b.ToString());
2654
 
2655
				return res;
2656
			}
2657
		}
2658
		#endregion other classes
2659
 
1288 dev 2660
    }
2661
 
1092 dev 2662
	public class LogMessages
2663
	{
2664
		private ArrayList messages = new ArrayList();
2665
		private ListBox   logBox;
2666
		private LogLevel  level = LogLevel.Debug;
2667
 
2668
		public LogLevel Level
2669
		{
2670
			get { return level; }
2671
			set { level = value; Update(); }
2672
		}
2673
 
2674
		public LogMessages(ListBox logBox)
2675
		{
2676
			this.logBox = logBox;
2677
		}
2678
 
2679
		public ArrayList Messages
2680
		{
2681
			get { return new ArrayList(messages); }
2682
		}
2683
 
2684
		public void Add(LogMessage message)
2685
		{
2686
			messages.Add(message);
2687
			if(Show(message))
2688
				logBox.TopIndex = logBox.Items.Count - 1;
2689
		}
2690
 
2691
		public void Clear()
2692
		{
2693
			messages.Clear();
2694
			logBox.Items.Clear();
2695
		}
2696
 
2697
		public void Update()
2698
		{
2699
			logBox.BeginUpdate();
2700
 
2701
			logBox.Items.Clear();
2702
			foreach(LogMessage message in messages)
2703
			{
2704
				Show(message);
2705
			}
2706
			logBox.TopIndex = logBox.Items.Count - 1;
2707
 
2708
			logBox.EndUpdate();
2709
		}
2710
 
2711
		private bool Show(LogMessage message)
2712
		{
2713
			if(message.Level > this.level) return false;
2714
 
2715
			try
2716
			{
2717
				logBox.Items.Add(message.ToString());
2718
			}
2719
			catch(ObjectDisposedException) {}
2720
 
2721
			return true;
2722
		}
2723
	}
2724
 
2725
	public class LogMessage
2726
	{
2727
		private TcpConnection tcp;
2728
		private LogLevel      level;
2729
		private string        message;
2730
		private Exception     exception;
2731
		private DateTime      timestamp = DateTime.Now;
2732
 
2733
		public TcpConnection Tcp
2734
		{
2735
			get { return tcp; }
2736
			set { tcp = value; }
2737
		}
2738
 
2739
		public LogLevel Level
2740
		{
2741
			get { return level; }
2742
			set { level = value; }
2743
		}
2744
 
2745
		public string Message
2746
		{
2747
			get { return message; }
2748
			set { message = value; }
2749
		}
2750
 
2751
		public Exception Exception
2752
		{
2753
			get { return exception; }
2754
			set { exception = value; }
2755
		}
2756
 
2757
		public DateTime Timestamp
2758
		{
2759
			get { return timestamp; }
2760
			set { timestamp = value; }
2761
		}
2762
 
2763
		public LogMessage(TcpConnection tcp, LogLevel level, string message, Exception exception)
2764
		{
2765
			this.tcp       = tcp;
2766
			this.level     = level;
2767
			this.message   = message;
2768
			this.exception = exception;
2769
		}
2770
 
2771
		public override string ToString()
2772
		{
2773
			string l = "     ";
2774
			switch(level)
2775
			{
2776
				case LogLevel.Debug:     l = "debug"; break;
2777
				case LogLevel.Info:      l = "info "; break;
2778
				case LogLevel.Important: l = "Imp  "; break;
2779
				case LogLevel.Warning:   l = "Warn "; break;
2780
				case LogLevel.Error:     l = "ERROR"; break;
2781
				case LogLevel.Critical:  l = "CRIT "; break;
2782
			}
2783
 
2784
			return (tcp == null ? "...." : tcp.Id) + " " + l + " " + timestamp.ToString("HH:mm:ss.ffff") + " "
2785
				+ (exception != null ? exception.Message : message);
2786
		}
2787
	}
2788
 
2789
	public enum TcpShowMode
2790
	{
2791
		ByDirection,
2792
		ByTime
2793
	}
1194 dev 2794
 
2795
	public class RecentItem : IComparable
2796
	{
2797
		private int listenPort;
2798
 
2799
		public int ListenPort
2800
		{
2801
			get { return listenPort; }
2802
			set { listenPort = value; }
2803
		}
2804
 
2805
		private string resendHost;
2806
 
2807
		public string ResendHost
2808
		{
2809
			get { return resendHost; }
2810
			set { resendHost = value; }
2811
		}
2812
 
2813
		private int resendPort;
2814
 
2815
		public int ResendPort
2816
		{
2817
			get { return resendPort; }
2818
			set { resendPort = value; }
2819
		}
2820
 
2821
		private DateTime timestamp;
2822
 
2823
		public DateTime Timestamp
2824
		{
2825
			get { return timestamp; }
2826
		}
2827
 
2828
		public RecentItem(int listenPort, string resendHost, int resendPort)
2829
		{
2830
			this.listenPort = listenPort;
2831
			this.resendHost = resendHost;
2832
			this.resendPort = resendPort;
2833
		}
2834
 
2835
		public override string ToString()
2836
		{
1197 dev 2837
			return string.Format("{0} to {1}:{2} at {3:HH:mm:ss.ff}",
1194 dev 2838
				listenPort, resendHost, resendPort, timestamp);
2839
		}
2840
 
2841
		public override bool Equals(object obj)
2842
		{
2843
			if(!(obj is RecentItem)) return false;
2844
 
2845
			RecentItem i2 = (RecentItem)obj;
2846
 
2847
			return (i2.listenPort == this.listenPort) && (i2.resendHost == this.resendHost)
2848
				&& (i2.resendPort == this.resendPort);
2849
		}
2850
 
2851
		public override int GetHashCode()
2852
		{
2853
			return this.resendHost.GetHashCode();
2854
		}
2855
 
2856
		public string SaveToRegistry()
2857
		{
1197 dev 2858
			return string.Format("{0}:{1}:{2}:{3}",
1194 dev 2859
				listenPort, resendPort, timestamp.Ticks, resendHost);
2860
		}
2861
 
2862
		public static RecentItem LoadFromRegistry(string str)
2863
		{
2864
			Regex re = new Regex(@"^(\d+):(\d+):(\d+):(.+)$");
2865
			Match m  = re.Match(str);
2866
			if(!m.Success) throw new Exception("Cannot parse recent item");
2867
 
1197 dev 2868
			RecentItem item = new RecentItem(int.Parse(m.Groups[1].Value),
1194 dev 2869
				m.Groups[4].Value, int.Parse(m.Groups[2].Value));
2870
 
2871
			item.timestamp = new DateTime(long.Parse(m.Groups[3].Value));
2872
 
2873
			return item;
2874
		}
2875
 
2876
		public void UpdateTimestamp()
2877
		{
2878
			timestamp = DateTime.Now;
2879
		}
2880
 
2881
		public void UpdateTimestamp(RecentItem second)
2882
		{
2883
			if(second.timestamp > timestamp)
2884
				timestamp = second.timestamp;
2885
		}
2886
 
2887
		#region IComparable Members
2888
 
2889
		int IComparable.CompareTo(object obj)
2890
		{
2891
			if(!(obj is RecentItem))
2892
				throw new Exception("Cannot compare");
2893
 
2894
			return this.timestamp.CompareTo(((RecentItem)obj).timestamp);
2895
		}
2896
 
2897
		#endregion
2898
	}
1092 dev 2899
}