?
Solved

How do I open a cached HTML file in an editor???

Posted on 1999-11-29
14
Medium Priority
?
311 Views
Last Modified: 2012-05-07
Hello everybody!  Been a while since I have dropped by.  Anyway, I got a good one this time (at least it seems rough to me :).  I have a notepad replacement I wrote a while back (mostly for my own use, just like notepad but shows the current row and col positions and a couple of other things I missed).  This is the problem.  When running IE on NT, if you go to the "view" menu and click "source", notepad opens with the contents of the current html file.  If I try to use my "replacement" notepad, it comes back with a "file not found" message.  I have been trying to debug this using a variety of tools, and basically I am stumped.  The file-name that notepad is actually opening doesnt really exist!  It is actually opening another file (with a LOOOONG screwy name, like most of the files in the temporary internet files folder) but calling it by a different name.  If you right click on the long screwy file in explorer, and view the properties, one of the properties is "cache name", which is the name that notepad opens it as.  I am guessing this is some kind of COM thing, like a compound document of something, but I am not sure.  If I try and open the file in my program by passing it the same path that notepad uses (after notepad has done it) it works fine.....?  So what is going on here.  Is notepad actually CREATING the file before opening it?  Or is it somehow converting the screwy path that IE passes it to something else?  I am totally stumped, and would really like to fix this as I would really like to use my editor for this task.  Any help would be GREATLY appreciated.  I am offering LOTS of points so only serious comments please.

Heath
0
Comment
Question by:heathprovost
  • 3
  • 3
  • 2
  • +5
14 Comments
 
LVL 2

Expert Comment

by:hubdog
ID: 2240169
i found in my computer
ie use d:\winnt\system32\notepad.exe to
open the soure file
not use d:\winnt\notepad.exe
when i replace the \system32\notepad.exe
with wordpad.exe(rename to notepad.exe)
ie use my wordpad.exe to open the temporary file but show error message
"d:\winnt\profiles\administror\temporary
can not find the file please confirm the path or filename right?"

i think that will be helpful to you

good luck
hubdog
0
 
LVL 5

Author Comment

by:heathprovost
ID: 2240195
yep, thats it...  At least I have confirmation on another machine of the problem.  You say even Wordpad cant do it...  Makes me think there must be something special about notepad.exe.....

Heath
0
 
LVL 3

Expert Comment

by:KE
ID: 2240315
Well, this directory is not a "normal" directory. I believe it's some kind of of structured storage.
I can't open any file within it with my notepad, so I guess that you will have to look at some API command to reach the files in the cache.

The reason for using structured storage is to minimize the cluster allocations on the HDD.

Regards
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 10

Expert Comment

by:Lischke
ID: 2240731
Yes, KE is right. The cache as well as the history folder can only be viewed using some COM interfaces. Here's my code I used in a demo to enumerate the history folder. To do the same for the cache I believe you'd need not many changes:

// The following declarations are taken from D4's ShlObj.pas (IQueryInfo) and VC +  + 6.0 comdef.h (IID_IQueryInfo).
// The IQueryInfo interface is used to get the original tooltip string for the entries in the explorer cache.
// The returned strings are stored as string reference in a node's data member. If this interface is not available
// then the data member remains nil and a default string is used instead.

const IID_IQueryInfo: TGUID = (D1:$00021500; D2:$0000; D3:$0000; D4:($C0, $00, $00, $00, $00, $00, $00, $46));

{$ifndef DFS_COMPILER_4_UP}
const SID_IQueryInfo = '{00021500-0000-0000-C000-000000000046}';

type
  {$ifdef DFS_COMPILER_3_UP}
    IQueryInfo = interface(IUnknown)
      [SID_IQueryInfo]
      function GetInfoTip(dwFlags: DWORD; var ppwszTip: PWideChar): HResult; stdcall;
      function GetInfoFlags(out pdwFlags: DWORD): HResult; stdcall;
    end;
  {$else} // Delphi 2
    IQueryInfo = class(IUnknown)
      function GetInfoTip(dwFlags: DWORD; var ppwszTip: PWideChar): HResult; virtual; stdcall; abstract;
      function GetInfoFlags(var pdwFlags: DWORD): HResult; virtual; stdcall; abstract;
    end;
  {$endif}
 
{$endif}
       
procedure TMainForm.FillTree3;

// fills tree3 with explorer history if available, SHGetSpecialFolderLocation might not work and/or CSIDL_HISTORY
// is not defined, thus I use an alternative way (by registry) to get the history folder

  //------------------------------------------------------------

  function DisplayToString(PIDL: PItemIDList; Display: TStrRet): String;

  begin
    case Display.uType of
      STRRET_CSTR:
        SetString(Result, Display.cStr, StrLen(Display.cStr));
      STRRET_WSTR:
        Result := WideCharToString(Display.pOleStr);
      STRRET_OFFSET:
        SetString(Result, PChar(PIDL) + Display.uOffset, StrLen(PChar(PIDL) + Display.uOffset));
    end;
  end;

  //------------------------------------------------------------

var WeekNode,
    SiteNode,
    URLNode: TTreeNTNode;
    History: PItemIDList;
    Malloc: IMalloc;
    Folder,
    HistoryFolder,
    WeekFolder,
    SiteFolder: IShellFolder;
    Eaten,
    Attrib: {$ifdef DFS_COMPILER_4_UP}
              Cardinal
            {$else}
              {$ifdef DFS_COMPILER_3_UP}
                Integer
              {$else}
                ULONG
              {$endif}
            {$endif};
    {$ifndef DFS_COMPILER_3_UP}
      Flags: UINT;
    {$endif}
    Key: HKEY;
    Buffer: array[0..4096] of Char;
    AType,
    Size: Integer;
    {$ifdef DFS_COMPILER_3_UP}
      Name: WideString;
    {$else}
      Name: String;
      PName: PWideChar;
    {$endif}
    HistoryEnumList,
    WeekEnumList,
    SiteEnumList: IEnumIDList;
    Week,
    Site,
    URL: PItemIDList;
    Fetched: {$ifdef DFS_COMPILER_4_UP}
               Cardinal
             {$else}
               {$ifdef DFS_COMPILER_3_UP}
                 Integer
               {$else}
                 ULONG
               {$endif}
             {$endif};
    Display: TStrRet;
    Icon: IExtractIcon;
    IconLarge,
    WeekIcon,
    SiteIcon,
    URLIcon: HICON;
    Index: Integer;
    TempIcon: TIcon;
    Info: IQueryInfo;
    InfoTip: PWideChar;
    FinalString,
    InfoTipStr: String;

begin
  // get task allocator to handle PIDLs
  SHGetMalloc(Malloc);
  History := nil;
  TempIcon := TIcon.Create;
  Tree3.Items.BeginUpdate;
  try
    // get desktop folder interface
    SHGetDesktopFolder(Folder);
    try
      // determine history folder name
      RegOpenKey(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders', Key);
      Size := SizeOf(Buffer);
      AType := REG_SZ;
      RegQueryValueEx(Key, 'History', nil, @AType, @Buffer, @Size);
      RegCloseKey(Key);
      // Is there a history folder on this machine?
      if StrLen(Buffer) > 0 then
      begin
        // convert folder path to wide string

        {$ifdef DFS_COMPILER_3_UP}
          Name := Buffer;
          // convert path to pidl
          Folder.ParseDisplayName(Handle, nil, PWideChar(Name), Eaten, History, Attrib);
        {$else}
          PName := StringToOLEStr(Buffer);
          try
            // convert path to pidl
            Folder.ParseDisplayName(Handle, nil, PName, Eaten, History, Attrib);        
          finally
            SysFreeString(PName);
          end;
        {$endif}

        // Are we succesfull?
        if assigned(History) then
        begin
          // get a shell folder to this pidl
          OLECheck(Folder.BindToObject(History, nil, IID_IShellFolder, Pointer(HistoryFolder)));
          try
            // now that we are in the history folder enumerate all site folders and their subitems;
            // we don't use findfirst/findnext here since the history folder does not contain real entries
            // but a binary file which must be parsed
            if Succeeded(HistoryFolder.EnumObjects(Handle, SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN, HistoryEnumList)) then
            begin
              // free dummy content of tree3
              Tree3.Items.Clear;
              SystemImages.Clear;
              WeekIcon := 0;
              SiteIcon := 0;
              URLIcon := 0;
              IconLarge := 0;
              while HistoryEnumList.Next(1, Week, Fetched) = S_OK do
              begin
                // for each subfolder do:
                // get display string as in IE
                HistoryFolder.GetDisplayNameOf(Week, STRRET_CSTR, Display);
                Name := DisplayToString(Week, Display);
                // add a corresponding tree node
                WeekNode := Tree3.Items.Add(nil, Name);
                // try getting the tooltip text
                Info := nil;
                HistoryFolder.GetUIObjectOf(Handle, 1, Week, IID_IQUERYINFO, nil, Pointer(Info));
                // interface available?
                if assigned(Info) then
                begin
                  Info.GetInfoTip(0, InfoTip);
                  // convert wide string to ansi string
                  {$ifdef DFS_COMPILER_3_UP}
                    InfoTipStr := InfoTip;
                  {$else}
                    InfoTipStr := WideCharToString(InfoTip);
                  {$endif}
                  // I'm lazy, let Delphi make the copy
                  WeekNode.Data := StrNew(PChar(InfoTipStr));
                  Malloc.Free(InfoTip);
                end;
                // get icon if not already retrieved
                if WeekIcon = 0 then
                begin
                  HistoryFolder.GetUIObjectOf(Handle, 1, Week, IID_IExtractIconA, nil, Pointer(Icon));
                  if assigned(Icon) then
                  begin
                    {$ifdef DFS_COMPILER_3_UP}
                      if Icon.GetIconLocation(GIL_FORSHELL, Buffer, SizeOf(Buffer), Index, Attrib) = NOERROR then
                      begin
                        if (Attrib and GIL_NOTFILENAME) <> 0
                    {$else}
                      if Icon.GetIconLocation(GIL_FORSHELL, Buffer, SizeOf(Buffer), Index, Flags) = NOERROR then
                      begin
                        if (Flags and GIL_NOTFILENAME) <> 0
                    {$endif}
                                                           then Icon.Extract(Buffer, Index, IconLarge, WeekIcon, MakeLParam(16, 16))
                                                           else ExtractIconEx(Buffer, Index, IconLarge, WeekIcon, 1);

                      ImageList_AddIcon(SystemImages.Handle, WeekIcon);
                      DestroyIcon(WeekIcon);
                    end
                    else WeekIcon := HICON(-1);
                  end
                  else WeekIcon := HICON(-1);
                end;
                WeekNode.ImageIndex := 0;
                WeekNode.SelectedIndex := 0;
                WeekNode.Color := clBtnFace;
                WeekNode.Font.Color := clBlack;

                // for each week entry get it's site entries
                OLECheck(HistoryFolder.BindToObject(Week, nil, IID_IShellFolder, Pointer(WeekFolder)));
                try
                  if Succeeded(WeekFolder.EnumObjects(Handle, SHCONTF_FOLDERS or SHCONTF_INCLUDEHIDDEN, WeekEnumList)) then
                  begin
                    while WeekEnumList.Next(1, Site, Fetched) = S_OK do
                    begin
                      // for each subfolder do:
                      // get display string as in IE
                      WeekFolder.GetDisplayNameOf(Site, STRRET_CSTR, Display);
                      // add a corresponding tree node
                      SiteNode := Tree3.Items.AddChild(WeekNode, DisplayToString(Site, Display));
                      // try getting the tooltip text
                      Info := nil;
                      WeekFolder.GetUIObjectOf(Handle, 1, Site, IID_IQUERYINFO, nil, Pointer(Info));
                      // interface available?
                      if assigned(Info) then
                      begin
                        Info.GetInfoTip(0, InfoTip);
                        // convert wide string to ansi string
                        {$ifdef DFS_COMPILER_3_UP}
                          InfoTipStr := InfoTip;
                        {$else}
                          InfoTipStr := WideCharToString(InfoTip);
                        {$endif}
                        // I'm lazy, let Delphi make the copy
                        SiteNode.Data := StrNew(PChar(InfoTipStr));
                        Malloc.Free(InfoTip);
                      end;
                      // get icon if not already retrieved
                      if SiteIcon = 0 then
                      begin
                        WeekFolder.GetUIObjectOf(Handle, 1, Site, IID_IExtractIconA, nil, Pointer(Icon));
                        if assigned(Icon) then
                        begin
                          IconLarge := 0;
                          {$ifdef DFS_COMPILER_3_UP}
                            if Icon.GetIconLocation(GIL_FORSHELL, Buffer, SizeOf(Buffer), Index, Attrib) = NOERROR then
                            begin
                              if (Attrib and GIL_NOTFILENAME) <> 0
                          {$else}
                            if Icon.GetIconLocation(GIL_FORSHELL, Buffer, SizeOf(Buffer), Index, Flags) = NOERROR then
                            begin
                              if (Flags and GIL_NOTFILENAME) <> 0
                          {$endif}
                                                                 then Icon.Extract(Buffer, Index, IconLarge, SiteIcon, MakeLParam(16, 16))
                                                                 else ExtractIconEx(Buffer, Index, IconLarge, SiteIcon, 1);

                            ImageList_AddIcon(SystemImages.Handle, SiteIcon);
                            DestroyIcon(SiteIcon);
                          end
                          else SiteIcon := HICON(-1);
                        end
                        else SiteIcon := HICON(-1);
                      end;
                      SiteNode.ImageIndex := 1;
                      SiteNode.SelectedIndex := 1;
                      SiteNode.Color := clBtnHighlight;
                      SiteNode.Font.Color := clBlack;

                      // for each site entry get it's URL entries
                      OLECheck(WeekFolder.BindToObject(Site, nil, IID_IShellFolder, Pointer(SiteFolder)));
                      try
                        if Succeeded(SiteFolder.EnumObjects(Handle, SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN, SiteEnumList)) then
                        begin
                          while SiteEnumList.Next(1, URL, Fetched) = S_OK do
                          begin
                            // for each item do:
                            // get display string as in IE, URLs are differently shown than the other nodes and since
                            // I want to show the tree exactly like IE I have to model the same behaviour

                            // try getting the tooltip text
                            Info := nil;
                            InfoTip := nil;
                            SiteFolder.GetUIObjectOf(Handle, 1, URL, IID_IQUERYINFO, nil, Pointer(Info));
                            // interface available?
                            if assigned(Info) then Info.GetInfoTip(0, InfoTip);

                            if assigned(InfoTip) then
                            begin
                              // convert wide string to ansi string
                              {$ifdef DFS_COMPILER_3_UP}
                                InfoTipStr := InfoTip;
                              {$else}
                                InfoTipStr := WideCharToString(InfoTip);
                              {$endif}
                              Malloc.Free(InfoTip);
                            end
                            else
                            begin
                              SiteFolder.GetDisplayNameOf(URL, STRRET_CSTR, Display);
                              InfoTipStr := DisplayToString(URL, Display);
                            end;

                            // find first line break
                            Size := Pos(#13, InfoTipStr);
                            if Size = 0 then FinalString := InfoTipStr
                                        else
                              if InfoTipStr[Size - 1] = #10 then FinalString := Copy(InfoTipStr, 1, Size - 2)
                                                            else FinalString := Copy(InfoTipStr, 1, Size - 1);

                            // now shorten the string until it fits into the client area, DisplayRect doesn't work
                            // here, since the node hasn't been displayed yet
                            Size := Tree3.Canvas.TextWidth(FinalString);
                            // we are on level 2, hence add the indentation plus some extra space for
                            // level 0 icon and offset
                            if Size + 2 * Tree3.Indent + 40 > Tree3.ClientWidth then
                            begin
                              while Size + 2 * Tree3.Indent + 40 > Tree3.ClientWidth do
                              begin
                                Delete(FinalString, Length(FinalString), 1);
                                Size := Tree3.Canvas.TextWidth(FinalString + '...');
                              end;
                              // add a corresponding tree node
                              URLNode := Tree3.Items.AddChild(SiteNode, FinalString + '...');
                            end
                            else URLNode := Tree3.Items.AddChild(SiteNode, FinalString);
                            // finally make a copy of the entire display string for the tooltip
                            URLNode.Data := StrNew(PChar(InfoTipStr));

                            // get icon if not already retrieved
                            if URLIcon = 0 then
                            begin
                              SiteFolder.GetUIObjectOf(Handle, 1, URL, IID_IExtractIconA, nil, Pointer(Icon));
                              if assigned(Icon) then
                              begin
                                IconLarge := 0;
                                {$ifdef DFS_COMPILER_3_UP}
                                  if Icon.GetIconLocation(GIL_FORSHELL, Buffer, SizeOf(Buffer), Index, Attrib) = NOERROR then
                                  begin
                                    if (Attrib and GIL_NOTFILENAME) <> 0
                                {$else}
                                  if Icon.GetIconLocation(GIL_FORSHELL, Buffer, SizeOf(Buffer), Index, Flags) = NOERROR then
                                  begin
                                    if (Flags and GIL_NOTFILENAME) <> 0
                                {$endif}
                                                                       then Icon.Extract(Buffer, Index, IconLarge, URLIcon, MakeLParam(16, 16))
                                                                       else ExtractIconEx(Buffer, Index, IconLarge, URLIcon, 1);

                                  ImageList_AddIcon(SystemImages.Handle, URLIcon);
                                  DestroyIcon(URLIcon);
                                end
                                else URLIcon := HICON(-1);
                              end
                              else URLIcon := HICON(-1);
                            end;
                            URLNode.ImageIndex := 2;
                            URLNode.SelectedIndex := 2;
                            URLNode.Color := clBtnHighlight;
                            URLNode.Font.Color := clBlack;
                            Malloc.Free(URL);
                          end;
                          SiteNode.AlphaSort;
                          {$ifdef DFS_COMPILER_2} SiteEnumList.Release; {$endif}
                        end;
                      finally
                        // here we need an explicit release, since we are going to use this interface several times
                        SiteFolder := nil;
                      end;

                      // finally free current week entry
                      Malloc.Free(Site);
                    end;
                    WeekNode.AlphaSort;
                    {$ifdef DFS_COMPILER_2} WeekEnumList.Release; {$endif}
                  end;
                finally
                  // here we need an explicit release, since we are going to use this interface several times
                  WeekFolder := nil;
                end;
                // finally free current week entry
                Malloc.Free(Week);
              end;
            end;
          finally
            {$ifdef DFS_COMPILER_2}
              HistoryFolder.Release;
            {$endif}
          end;
        end;
      end;
    finally
      {$ifdef DFS_COMPILER_2}
        Folder.Release;
      {$endif}
    end;
  finally
    Malloc.Free(History);
    {$ifdef DFS_COMPILER_2}
      Malloc.Release;
    {$endif}
    TempIcon.Free;
    Tree3.Items.EndUpdate;
  end;
end;


What I'd like to know is how you replaced notepad for viewing source files in IE? Or did you replace it with your own and just named it also notepad?

Ciao, Mike
0
 
LVL 17

Expert Comment

by:inthe
ID: 2241146
listening..
0
 
LVL 3

Accepted Solution

by:
vladika earned 4000 total points
ID: 2241502
I used Regmon utility from www.sysinternals.com to view how IE work with registry.
First IE query for HKLM\Software\Microsoft\Internet Explorer\View Source Editor\Editor Name value from registry.
Then it uses this value to query HKLM\Software\Microsoft\Windows\CurrentVersion\AppPaths\YourEditorName value
If it found your viewer program then it run it. First parameter is html file.
If it cannot found your viewer program it run default viewer (notepad).
BUT I think there is error in IE. When IE pass parameter to your program it does not quoted it with " char. This is  error obviously, becouse your program treat ONLY part of (before first space) file name as html file name. BTW This is explain why hubdog receive 'd:\winnt\profiles\administror\temporary' message.
To demonstrate this I create small demo

program IETest;

uses
  SysUtils,
  Windows;

{$R *.RES}

var
  S: string;
  I: Integer;
begin
  S := '';
  for I := 1 to ParamCount do
    S := S + Format('%d: %s'#13#10, [I, ParamStr(I)]);
  MessageBox(0, PChar(S), '', 0);
end.

If you set this program as source viewer you will see next messages on screen when click 'Show source' in IE
1: C:\WinNT\Profiles\Administrator\Temporary
2: Internet
3: Files\Content.IE5\.....

So, You receive 3 parameter instead of 1!

Solution is to treat all parameters as one!
i.e. RealFileName := Param(1) + ' ' + Param(2) + ' ' + .. ;// this is just pseudo code, sorry

0
 
LVL 4

Expert Comment

by:jeurk
ID: 2243067
Hi,
This is the source of a program
I created to load ultraedit instead of
notepad, it is working perfectly.
If you want handle more things like
printing you have to know that notepad
can be called with params like /p
for printing a file.
under NT notepad stays in \winnt\
and \winnt\system32\
so remember to change the two occurence.

CU


this is only a project. No form.

-------------------------------------
PROGRAM Notepad;

USES
     windows, shellapi, registry;
VAR
     ini: tregistry;
     nimpo: STRING;
     tutu : STRING;
     c:integer;
{$R *.RES}

BEGIN
     ini := tregistry.Create;
     ini.RootKey := HKEY_CLASSES_ROOT;
     ini.OpenKey('', FALSE);
     ini.OpenKey('UltraEdit-32 Document\shell\open\command', FALSE);
     nimpo := ini.readString('');
     nimpo:=copy(nimpo, 2, length(nimpo)-7);
     
     for  c:= 1 to ParamCount do
     begin
       tutu:=tutu+' '+pchar(paramstr(c))
     end;
//     MessageDlg(tutu,mtError,[mbOK],0);
     shellExecute(0, pchar('open'), PChar(nimpo), Pchar(tutu), NIL, SW_SHOWNORMAL);

     ini.Free;
END.
0
 
LVL 3

Expert Comment

by:sburck
ID: 2243612
listening...
0
 
LVL 5

Author Comment

by:heathprovost
ID: 2244272
Well you nailed that one...  I should have noticed it before, but with all this funny cache name business I was distracted from the simple explanation. Thanks, I got everything working now.

Heath
0
 
LVL 4

Expert Comment

by:jeurk
ID: 2245978
Bouhh...
So much points missed just because
I was at work and did not have my
small prog on my computer.

I'll keep trying ;)
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2246050
..and really easily earned points (was that worth 1000 points plus an A grading?). vladika read between the lines and understood so the real question, so I just wasted my time here :-/

Ciao, Mike
0
 
LVL 5

Author Comment

by:heathprovost
ID: 2246109
Lischke, I really did appreciate your comment, and I promise to give you first crack on my next question here.  If I had thought the answer was something that simple, I wouldnt have offered so many points.  But I was REALLY stumped, and wanted to get some attention.  vladika DID give a concise and correct answer, so I certainly cant deny him the points just because I overlooked something stupid on my end.  What comes around goes around, and I will definitely give you first crack at my next problem.  I answer a few questions here also, and I realize you spent some time coming up with the code you gave.  No hard feelings OK?

Heath
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2246130
It's okay :-) Just jealousy on my side... My point is and was always to give the fittest solution the points not the one with the most text, although it happens often the other way around here.

Until next time...

Ciao, Mike
0
 
LVL 3

Expert Comment

by:vladika
ID: 2246140
Lischke, you had time to 'read between lines', had not it? I added comment after you.
0

Featured Post

[Webinar] Improve your customer journey

A positive customer journey is important in attracting and retaining business. To improve this experience, you can use Google Maps APIs to increase checkout conversions, boost user engagement, and optimize order fulfillment. Learn how in this webinar presented by Dito.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
There may be issues when you are trying to access Outlook or send & receive emails or due to Outlook crash which leads to corrupt or damaged PST file. To eliminate the corruption from your PST file, you need to repair the corrupt Outlook PST file. U…
The video provides a quick and easy steps to migrate MBOX file to well known Outlook PST and Office 365. Besides this, it also supports and migrates more than 20 email clients of MBOX which include AppleMail, Opera, Thunderbird and SeaMonkey effortl…

599 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question