Skip to content

Commit 311fdff

Browse files
Cross Frame Search with Ctrl+F3 (#215)
* stub in new ctrl handler * fill in current frame portion of ctrl+f3 * combine search functions * simplify search invocation logic * Start simplifying ParseHTTPPayload * Simplify ParseHTTPPayload further * simplify further * simplify * Simplify * implement cross frame seach * remove "Number" from SessionNavigator * simplify sessions handling * Move import event to single entry point Always init the session navigator * Make SessionNavigator init on demand * reset navigator on new sessions * Make SessionNavigator a lightwight singleton * simplify * simplify * Ensure visible on matches and set status text * better palceholder text * simplify * simplify * simplify * simplify * slight tweaks
1 parent f356d19 commit 311fdff

File tree

8 files changed

+265
-202
lines changed

8 files changed

+265
-202
lines changed

MAPIInspector/Source/MAPIControl.Designer.cs

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MAPIInspector/Source/MAPIControl.Events.cs

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Fiddler;
2+
using MAPIInspector.Parsers;
13
using System;
24
using System.Text;
35
using System.Windows.Forms;
@@ -6,6 +8,10 @@ namespace MapiInspector
68
{
79
public partial class MAPIControl
810
{
11+
public static readonly string SearchDefaultText = "Search (Ctrl+F) F3 to search. Hold SHIFT to search backwards. Hold CTRL to search across frames.";
12+
private readonly System.Drawing.Color SearchDefaultColor = System.Drawing.Color.Gray;
13+
private readonly System.Drawing.Color SearchNormalColor = System.Drawing.Color.Black;
14+
915
private void InitializeContextMenus()
1016
{
1117
// TreeView context menu
@@ -69,6 +75,7 @@ private string GetNodeText(TreeNode node)
6975
{
7076
return CleanString(position.SourceBlock.Text);
7177
}
78+
7279
return CleanString(node.Text);
7380
}
7481

@@ -207,43 +214,47 @@ private void CropsHexBox_CopyHex_Click(object sender, EventArgs e)
207214

208215
private void SearchButton_Click(object sender, EventArgs e)
209216
{
210-
bool bIsShift = (ModifierKeys & Keys.Shift) == Keys.Shift;
211-
PerformSearch(bIsShift);
217+
var isCtrl = (ModifierKeys & Keys.Control) == Keys.Control;
218+
var isShift = (ModifierKeys & Keys.Shift) == Keys.Shift;
219+
PerformSearch(isShift, isCtrl);
220+
212221
}
213222

214223
private void SearchTextBox_KeyDown(object sender, KeyEventArgs e)
215224
{
216225
bool bEnter = e.KeyCode == Keys.Enter;
217-
bool bShiftEnter = (e.KeyCode == Keys.Enter) && (e.Modifiers == Keys.Shift);
226+
bool isCtrl = (ModifierKeys & Keys.Control) == Keys.Control;
227+
bool isShift = (ModifierKeys & Keys.Shift) == Keys.Shift;
218228

219-
if (bEnter || bShiftEnter)
229+
if (bEnter)
220230
{
221-
PerformSearch(e.Modifiers == Keys.Shift);
231+
PerformSearch(isShift, isCtrl);
222232
e.Handled = true;
223233
e.SuppressKeyPress = true;
224234
}
225235
}
226236

227237
private void SearchTextBox_GotFocus(object sender, EventArgs e)
228238
{
229-
if (searchTextBox.Text == "Search (Ctrl+F)")
239+
if (searchTextBox.Text == SearchDefaultText)
230240
{
231241
searchTextBox.Text = "";
242+
searchTextBox.ForeColor = SearchNormalColor;
232243
}
233244
}
234245

235246
private void SearchTextBox_LostFocus(object sender, EventArgs e)
236247
{
237248
if (string.IsNullOrWhiteSpace(searchTextBox.Text))
238249
{
239-
searchTextBox.Text = "Search (Ctrl+F)";
250+
searchTextBox.Text = SearchDefaultText;
251+
searchTextBox.ForeColor = SearchDefaultColor;
240252
}
241253
}
242254

243-
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
255+
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, Keys keyData)
244256
{
245-
bool isF3 = keyData == Keys.F3;
246-
bool isShiftF3 = keyData == (Keys.Shift | Keys.F3);
257+
bool isF3 = keyData.HasFlag(Keys.F3);
247258
bool isCtrlF = keyData == (Keys.Control | Keys.F);
248259
bool isCtrlRight = keyData == (Keys.Control | Keys.Right);
249260

@@ -287,43 +298,74 @@ protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
287298
return true;
288299
}
289300

290-
if (isF3 || isShiftF3)
301+
if (isF3)
291302
{
292-
PerformSearch(keyData.HasFlag(Keys.Shift));
303+
PerformSearch(keyData.HasFlag(Keys.Shift), keyData.HasFlag(Keys.Control));
293304
return true;
294305
}
295306

296307
return base.ProcessCmdKey(ref msg, keyData);
297308
}
298309

299-
private void PerformSearch(bool searchUp)
310+
// Combined search logic for single and multi-frame search
311+
private void PerformSearch(bool searchUp, bool searchFrames)
300312
{
301-
string searchText = searchTextBox.Text.Trim();
302-
if (mapiTreeView.Nodes.Count == 0 ||
303-
string.IsNullOrEmpty(searchText) ||
304-
searchText == "Search (Ctrl+F)")
313+
var searchText = searchTextBox.Text.Trim();
314+
if (string.IsNullOrEmpty(searchText) || searchText == SearchDefaultText) return;
315+
316+
FiddlerApplication.UI.SetStatusText($"Searching for {searchText}");
317+
var startNode = mapiTreeView?.SelectedNode;
318+
if (startNode == null && mapiTreeView?.Nodes.Count > 0)
305319
{
306-
return;
320+
startNode = mapiTreeView.Nodes[0];
307321
}
308322

309-
var startNode = mapiTreeView.SelectedNode ?? mapiTreeView.Nodes[0];
310-
if (startNode == null)
311-
return;
323+
if (startNode != null)
324+
{
325+
var nodes = mapiTreeView.Nodes;
326+
TreeNode foundNode = searchUp
327+
? FindPrevNode(nodes, startNode, searchText, !searchFrames)
328+
: FindNextNode(nodes, startNode, searchText, !searchFrames);
312329

313-
var foundNode = searchUp
314-
? FindPrevNode(mapiTreeView.Nodes, startNode, searchText)
315-
: FindNextNode(mapiTreeView.Nodes, startNode, searchText);
330+
if (foundNode != null)
331+
{
332+
mapiTreeView.SelectedNode = foundNode;
333+
mapiTreeView.Focus();
334+
foundNode.EnsureVisible();
335+
return;
336+
}
337+
}
316338

317-
if (foundNode != null)
339+
if (searchFrames)
318340
{
319-
mapiTreeView.SelectedNode = foundNode;
320-
mapiTreeView.Focus();
321-
foundNode.EnsureVisible();
341+
var currentSession = Inspector.session;
342+
while (currentSession != null)
343+
{
344+
var nextSession = searchUp ? currentSession?.Previous() : currentSession?.Next();
345+
if (nextSession == null) break;
346+
var parseResult = MAPIParser.ParseHTTPPayload(nextSession, Inspector.Direction, out var bytes);
347+
var rootNode = new TreeNode();
348+
var node = BaseStructure.AddBlock(parseResult, false);
349+
rootNode.Nodes.Add(node);
350+
var foundMatch = searchUp
351+
? FindPrevNode(rootNode.Nodes, node, searchText, true)
352+
: FindNextNode(rootNode.Nodes, node, searchText, true);
353+
if (foundMatch != null)
354+
{
355+
FiddlerApplication.UI.SelectSessionsMatchingCriteria(s => s.id == nextSession.id);
356+
nextSession.ViewItem.EnsureVisible();
357+
return;
358+
}
359+
360+
currentSession = nextSession;
361+
}
322362
}
363+
364+
FiddlerApplication.UI.SetStatusText("No match found");
323365
}
324366

325367
// Find next node (downwards, wraps around)
326-
private TreeNode FindNextNode(TreeNodeCollection nodes, TreeNode startNode, string searchText)
368+
private TreeNode FindNextNode(TreeNodeCollection nodes, TreeNode startNode, string searchText, bool wrap)
327369
{
328370
bool foundStart = false;
329371
TreeNode firstMatch = null;
@@ -335,18 +377,20 @@ private TreeNode FindNextNode(TreeNodeCollection nodes, TreeNode startNode, stri
335377
continue;
336378
}
337379

338-
if (foundStart && GetNodeText(node).IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)
339-
return node;
340-
if (firstMatch == null && GetNodeText(node).IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)
341-
firstMatch = node;
380+
if (GetNodeText(node).IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)
381+
{
382+
if (foundStart)
383+
return node;
384+
if (firstMatch == null)
385+
firstMatch = node;
386+
}
342387
}
343388

344-
// Wrap around
345-
return firstMatch;
389+
return wrap ? firstMatch : null;
346390
}
347391

348392
// Find previous node (upwards, wraps around)
349-
private TreeNode FindPrevNode(TreeNodeCollection nodes, TreeNode startNode, string searchText)
393+
private TreeNode FindPrevNode(TreeNodeCollection nodes, TreeNode startNode, string searchText, bool wrap)
350394
{
351395
TreeNode lastMatch = null;
352396
foreach (var node in FlattenNodes(nodes))
@@ -357,8 +401,7 @@ private TreeNode FindPrevNode(TreeNodeCollection nodes, TreeNode startNode, stri
357401
lastMatch = node;
358402
}
359403

360-
// Wrap around: if nothing before, search from end
361-
if (lastMatch == null)
404+
if (lastMatch == null && wrap)
362405
{
363406
foreach (var node in FlattenNodes(nodes))
364407
{

MAPIInspector/Source/MAPIInspector.cs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using Be.Windows.Forms;
77
using BlockParser;
88
using Fiddler;
9-
using global::MAPIInspector.Parsers;
9+
using MAPIInspector.Parsers;
1010
using static MapiInspector.MAPIParser;
1111

1212
namespace MapiInspector
@@ -54,7 +54,7 @@ public abstract class MAPIInspector : Inspector2
5454
/// <summary>
5555
/// Gets the direction of the traffic
5656
/// </summary>
57-
public MAPIParser.TrafficDirection Direction
57+
public TrafficDirection Direction
5858
{
5959
get
6060
{
@@ -142,6 +142,8 @@ public override void AddToTab(TabPage o)
142142
MAPIViewControl.AfterSelect -= TreeView_AfterSelect;
143143
MAPIViewControl.AfterSelect += TreeView_AfterSelect;
144144
DecodingContext dc = new DecodingContext();
145+
FiddlerApplication.OnLoadSAZ += AfterCallDoImport;
146+
FiddlerApplication.AfterSessionComplete += (Session oSession) => SessionExtensions.AllSessionsNavigator.Init();
145147
}
146148

147149
/// <summary>
@@ -353,6 +355,7 @@ public void ToggleDebug()
353355
private void UpdateView()
354356
{
355357
Clear();
358+
SessionExtensions.AllSessionsNavigator.Init();
356359
byte[] bytesForHexView;
357360
Block parserResult;
358361
IsLooperCall = false;
@@ -362,23 +365,11 @@ private void UpdateView()
362365

363366
if (IsMapihttp)
364367
{
365-
List<Session> allSessionsList = new List<Session>();
366-
Session session0 = new Session(new byte[0], new byte[0]);
367-
Session[] sessionsInFiddler = FiddlerApplication.UI.GetAllSessions();
368-
allSessionsList.AddRange(sessionsInFiddler);
369-
FiddlerApplication.OnLoadSAZ += AfterCallDoImport;
370-
allSessionsList.Sort(delegate (Session p1, Session p2)
371-
{
372-
return p1.id.CompareTo(p2.id);
373-
});
374-
allSessionsList.Insert(0, session0);
375-
SessionExtensions.AllSessionsNavigator = new SessionNavigator(allSessionsList.ToArray());
376-
377368
try
378369
{
379370
if (Direction == TrafficDirection.In)
380371
{
381-
parserResult = ParseHTTPPayload(BaseHeaders, session, session.requestBodyBytes, TrafficDirection.In, out bytesForHexView);
372+
parserResult = ParseHTTPPayload(session, TrafficDirection.In, out bytesForHexView);
382373
}
383374
else
384375
{
@@ -388,7 +379,7 @@ private void UpdateView()
388379
return;
389380
}
390381

391-
parserResult = ParseHTTPPayload(BaseHeaders, session, session.responseBodyBytes, TrafficDirection.Out, out bytesForHexView);
382+
parserResult = ParseHTTPPayload(session, TrafficDirection.Out, out bytesForHexView);
392383
}
393384

394385
DisplayObject(parserResult, bytesForHexView);
@@ -422,11 +413,11 @@ private void UpdateView()
422413
/// <param name="autoCaseName">The test case name to parse</param>
423414
/// <param name="allRops">All ROPs contained in list</param>
424415
/// <returns>Parse result, true means success</returns>
425-
public bool ParseCaptureFile(Fiddler.Session[] sessionsFromCore, string pathName, string autoCaseName, out List<string> allRops)
416+
public bool ParseCaptureFile(Session[] sessionsFromCore, string pathName, string autoCaseName, out List<string> allRops)
426417
{
427418
var errorStringList = new List<string>();
428419
StringBuilder stringBuilder = new StringBuilder();
429-
SessionExtensions.AllSessionsNavigator = new SessionNavigator(sessionsFromCore);
420+
SessionExtensions.AllSessionsNavigator.Init(sessionsFromCore);
430421

431422
DecodingContext decodingContext = new DecodingContext();
432423
Partial.ResetPartialParameters();
@@ -446,12 +437,11 @@ public bool ParseCaptureFile(Fiddler.Session[] sessionsFromCore, string pathName
446437
IsLooperCall = false;
447438
Partial.ResetPartialParameters();
448439
BaseHeaders = session.RequestHeaders;
449-
byte[] bytes;
450-
object obj = ParseHTTPPayload(BaseHeaders, session, session.requestBodyBytes, TrafficDirection.In, out bytes);
440+
object obj = ParseHTTPPayload(session, TrafficDirection.In, out byte[] bytes);
451441
JsonResult += Utilities.ConvertCSharpToJson(i, isRequest: true, obj);
452442
if (session["X-ResponseCode"] == "0")
453443
{
454-
object obj2 = ParseHTTPPayload(BaseHeaders, session, session.responseBodyBytes, TrafficDirection.Out, out bytes);
444+
object obj2 = ParseHTTPPayload(session, TrafficDirection.Out, out byte[] bytes2);
455445
JsonResult += Utilities.ConvertCSharpToJson(i, isRequest: false, obj2);
456446
}
457447
}

MAPIInspector/Source/MAPIInspector.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@
754754
<DesignTime>True</DesignTime>
755755
<DependentUpon>Resources.resx</DependentUpon>
756756
</Compile>
757+
<Compile Include="SessionDebugView.cs" />
757758
<Compile Include="SessionExtensions.cs" />
758759
<Compile Include="SessionNavigator.cs" />
759760
<Compile Include="Utilities.cs" />

0 commit comments

Comments
 (0)