jens-maus/yam

View on GitHub
src/mui/SearchMailWindow.c

Summary

Maintainability
Test Coverage
/***************************************************************************

 YAM - Yet Another Mailer
 Copyright (C) 1995-2000 Marcel Beck
 Copyright (C) 2000-2022 YAM Open Source Team

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 YAM Official Support Site :  http://www.yam.ch
 YAM OpenSource project    :  http://sourceforge.net/projects/yamos/

 $Id$

 Superclass:  MUIC_Window
 Description: Window to search for mails in all folders

***************************************************************************/

#include "SearchMailWindow_cl.h"

#include <string.h>
#include <proto/muimaster.h>
#include <libraries/iffparse.h>
#include <mui/BetterString_mcc.h>
#include <mui/NBalance_mcc.h>
#include <mui/NList_mcc.h>
#include <mui/NListtree_mcc.h>
#include <mui/NListview_mcc.h>

#include "SDI_hook.h"

#include "YAM.h"
#include "YAM_find.h"
#include "YAM_mainFolder.h"

#include "mui/FilterPopupList.h"
#include "mui/FolderRequestListtree.h"
#include "mui/MainFolderListtree.h"
#include "mui/MainMailList.h"
#include "mui/ReadWindow.h"
#include "mui/SearchControlGroup.h"

#include "Config.h"
#include "FolderList.h"
#include "Locale.h"
#include "MailList.h"
#include "MethodStack.h"
#include "MUIObjects.h"
#include "Requesters.h"
#include "Threads.h"

#include "Debug.h"

/* CLASSDATA
struct Data
{
  Object *LT_FOLDERS;
  Object *GR_SEARCH;
  Object *LV_MAILS;
  Object *GR_PAGE;
  Object *GA_PROGRESS;
  Object *BT_SEARCH;
  Object *BT_SELECTACTIVE;
  Object *BT_SELECT;
  Object *BT_READ;

  struct Hook searchOptFromFilterPopupHook;

  BOOL active;
  BOOL abort;
  BOOL clearOnEnd;

  char progressText[SIZE_DEFAULT];
  char screenTitle[SIZE_DEFAULT];
};
*/

/// InitFilterPopupList
//  Creates a popup list of configured filters
HOOKPROTONHNP(InitFilterPopupList, ULONG, Object *listview)
{
  Object *list;

  ENTER();

  if((list = (Object *)xget(listview, MUIA_NListview_NList)) != NULL)
    DoMethod(list, MUIM_FilterPopupList_Popup);

  RETURN(TRUE);
  return TRUE;
}
MakeStaticHook(InitFilterPopupListHook, InitFilterPopupList);

///
/// SearchOptFromFilterPopup
//  Gets search options from selected filter
HOOKPROTONP(SearchOptFromFilterPopup, void, Object *listview)
{
  struct Data *data = (struct Data *)hook->h_Data;
  Object *list;

  ENTER();

  if((list = (Object *)xget(listview, MUIA_NListview_NList)) != NULL)
  {
    struct FilterNode *filter;

    // get the currently active filter
    DoMethod(list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &filter);
    if(filter != NULL)
    {
      struct RuleNode *rule;

      if((rule = GetFilterRule(filter, 0)) != NULL)
        DoMethod(data->GR_SEARCH, MUIM_SearchControlGroup_RuleToGUI, rule);
    }
  }

  LEAVE();
}
MakeStaticHook(SearchOptFromFilterPopupHook, SearchOptFromFilterPopup);

///

/* Overloaded Methods */
/// OVERLOAD(OM_NEW)
OVERLOAD(OM_NEW)
{
  Object *LT_FOLDERS;
  Object *GR_SEARCH;
  Object *LV_MAILS;
  Object *GR_PAGE;
  Object *GA_PROGRESS;
  Object *BT_SEARCH;
  Object *BT_SELECTACTIVE;
  Object *BT_SELECT;
  Object *BT_READ;
  Object *BT_ALL;
  Object *BT_NONE;
  Object *PO_FROMRULE;
  Object *LV_FROMRULE;
  Object *BT_TORULE;
  Object *BT_ABORT;

  ENTER();

  if((obj = DoSuperNew(cl, obj,

    MUIA_HelpNode, "Windows/Searchwindow",
    MUIA_Window_ID, MAKE_ID('F','I','N','D'),
    WindowContents, VGroup,

      Child, HGroup,
        GroupSpacing(0),
        MUIA_VertWeight, 1,
        Child, VGroup, GroupFrameT(tr(MSG_FI_FindIn)),
          MUIA_HorizWeight, 1,
          Child, NListviewObject,
            MUIA_CycleChain, 1,
            MUIA_NListview_NList, LT_FOLDERS = FolderRequestListtreeObject,
              InputListFrame,
              MUIA_NList_AutoVisible, TRUE,
              MUIA_NList_AdjustWidth, TRUE,
              MUIA_NListtree_MultiSelect, TRUE,
            End,
          End,
          Child, HGroup,
            Child, BT_ALL = MakeButton(tr(MSG_FI_AllFolders)),
            Child, BT_NONE = MakeButton(tr(MSG_FI_NOFOLDERS)),
          End,
        End,
        Child, NBalanceObject,
          MUIA_ObjectID, MAKE_ID('B','0','0','5'),
          MUIA_Balance_Quiet, TRUE,
        End,
        Child, VGroup, GroupFrameT(tr(MSG_FI_FindWhat)),
          MUIA_HorizWeight, 10,
          Child, VSpace(0),
          Child, GR_SEARCH = SearchControlGroupObject,
            MUIA_SearchControlGroup_RemoteFilterMode, FALSE,
            MUIA_SearchControlGroup_SingleRule, TRUE,
            MUIA_SearchControlGroup_AllowSpamStatus, C->SpamFilterEnabled,
          End,
          Child, ColGroup(2),
            Child, PO_FROMRULE = PopobjectObject,
              MUIA_Popstring_Button, MakeButton(tr(MSG_FI_UseFilter)),
              MUIA_Popobject_Object, NListviewObject,
                MUIA_NListview_NList, LV_FROMRULE = FilterPopupListObject,
                End,
              End,
            End,
            Child, BT_TORULE = MakeButton(tr(MSG_FI_AddAsFilter)),
          End,
          Child, VSpace(0),
        End,
      End,
      Child, NBalanceObject,
        MUIA_ObjectID, MAKE_ID('B','0','0','6'),
        MUIA_Balance_Quiet, TRUE,
      End,
      Child, VGroup, GroupFrameT(tr(MSG_FI_Results)),
        MUIA_VertWeight, 100,
        Child, NListviewObject,
          MUIA_CycleChain, TRUE,
          MUIA_NListview_NList, LV_MAILS = MainMailListObject,
            //MUIA_ObjectID,       MAKE_ID('N','L','0','3'),
            MUIA_ContextMenu,    NULL,
            MUIA_NList_Format,   "COL=9 W=-1 MIW=-1 PCS=C BAR, COL=1 W=35 PCS=R BAR, COL=3 W=55 PCS=R BAR, COL=4 W=-1 MIW=-1 BAR, COL=7 W=-1 MIW=-1 BAR, COL=5 W=10 MIW=-1 P=\33r BAR",
            MUIA_MainMailList_HandleDoubleClick, FALSE,
            MUIA_MainMailList_InSearchWindow, TRUE,
          End,
        End,
      End,
      Child, GR_PAGE = PageGroup,
        Child, HGroup,
          Child, BT_SEARCH = MakeButton(tr(MSG_FI_StartSearch)),
          Child, BT_SELECTACTIVE = MakeButton(tr(MSG_FI_SELECTACTIVE)),
          Child, BT_SELECT = MakeButton(tr(MSG_FI_SelectMatched)),
          Child, BT_READ = MakeButton(tr(MSG_FI_ReadMessage)),
        End,
        Child, HGroup,
          Child, GA_PROGRESS = GaugeObject,
            MUIA_HorizWeight, 200,
            GaugeFrame,
            MUIA_Gauge_Horiz,TRUE,
          End,
          Child, BT_ABORT = MakeButton(tr(MSG_FI_Abort)),
        End,
      End,

    End,

    TAG_MORE, inittags(msg))) != NULL)
  {
    GETDATA;

    DoMethod(G->App, OM_ADDMEMBER, obj);

    data->LT_FOLDERS = LT_FOLDERS;
    data->GR_SEARCH = GR_SEARCH;
    data->LV_MAILS = LV_MAILS;
    data->GR_PAGE = GR_PAGE;
    data->GA_PROGRESS = GA_PROGRESS;
    data->BT_SEARCH = BT_SEARCH;
    data->BT_SELECTACTIVE = BT_SELECTACTIVE;
    data->BT_SELECT = BT_SELECT;
    data->BT_READ = BT_READ;

    InitHook(&data->searchOptFromFilterPopupHook, SearchOptFromFilterPopupHook, data);
    xset(PO_FROMRULE, MUIA_Popobject_ObjStrHook, &data->searchOptFromFilterPopupHook,
                      MUIA_Popobject_StrObjHook, &InitFilterPopupListHook,
                      MUIA_Popobject_WindowHook, &PO_WindowHook);

    set(BT_SELECTACTIVE, MUIA_Disabled, TRUE);
    set(BT_SELECT,       MUIA_Disabled, TRUE);
    set(BT_READ,         MUIA_Disabled, TRUE);

    xset(obj, MUIA_Window_DefaultObject, LV_MAILS,
              MUIA_Window_Title, tr(MSG_FI_FindMessages),
              MUIA_Window_ScreenTitle, CreateScreenTitle(data->screenTitle, sizeof(data->screenTitle), tr(MSG_FI_FindMessages)));

    SetHelp(LT_FOLDERS,       MSG_HELP_FI_LV_FOLDERS);
    SetHelp(BT_ALL,           MSG_HELP_FI_BT_ALL);
    SetHelp(BT_NONE,          MSG_HELP_FI_BT_NONE);
    SetHelp(PO_FROMRULE,      MSG_HELP_FI_PO_FROMRULE);
    SetHelp(BT_TORULE,        MSG_HELP_FI_BT_TORULE);
    SetHelp(BT_SEARCH,        MSG_HELP_FI_BT_SEARCH);
    SetHelp(BT_SELECTACTIVE,  MSG_HELP_FI_BT_SELECTACTIVE);
    SetHelp(BT_SELECT,        MSG_HELP_FI_BT_SELECT);
    SetHelp(BT_READ,          MSG_HELP_FI_BT_READ);
    SetHelp(BT_ABORT,         MSG_HELP_FI_BT_ABORT);

    DoMethod(BT_ABORT,        MUIM_Notify, MUIA_Pressed,             FALSE,          obj,              1, METHOD(Abort));
    DoMethod(LV_FROMRULE,     MUIM_Notify, MUIA_NList_DoubleClick,   TRUE,           PO_FROMRULE,      2, MUIM_Popstring_Close, TRUE);
    DoMethod(BT_ALL,          MUIM_Notify, MUIA_Pressed,             FALSE,          LT_FOLDERS,       5, MUIM_NListtree_Select, MUIV_NListtree_Select_All, MUIV_NListtree_Select_On, MUIF_NONE, NULL);
    DoMethod(BT_NONE,         MUIM_Notify, MUIA_Pressed,             FALSE,          LT_FOLDERS,       5, MUIM_NListtree_Select, MUIV_NListtree_Select_All, MUIV_NListtree_Select_Off, MUIF_NONE, NULL);
    DoMethod(BT_TORULE,       MUIM_Notify, MUIA_Pressed,             FALSE,          obj,              1, METHOD(CreateFilter));
    DoMethod(BT_SEARCH,       MUIM_Notify, MUIA_Pressed,             FALSE,          obj,              1, METHOD(Search));
    DoMethod(BT_SELECT,       MUIM_Notify, MUIA_Pressed,             FALSE,          obj,              1, METHOD(SelectMails));
    DoMethod(BT_SELECTACTIVE, MUIM_Notify, MUIA_Pressed,             FALSE,          obj,              1, METHOD(SwitchFolder));
    DoMethod(LV_MAILS,        MUIM_Notify, MUIA_NList_DoubleClick,   MUIV_EveryTime, obj,              1, METHOD(ReadMail));
    DoMethod(BT_READ,         MUIM_Notify, MUIA_Pressed,             FALSE,          obj,              1, METHOD(ReadMail));
    DoMethod(obj,             MUIM_Notify, MUIA_Window_CloseRequest, TRUE,           MUIV_Notify_Self, 1, METHOD(Close));

    // Lets have the Listview sorted by Reverse Date by default
    set(LV_MAILS, MUIA_NList_SortType, (4 | MUIV_NList_SortTypeAdd_2Values));
  }

  RETURN((IPTR)obj);
  return (IPTR)obj;
}

///
/// OVERLOAD(OM_GET)
OVERLOAD(OM_GET)
{
  GETDATA;
  IPTR *store = ((struct opGet *)msg)->opg_Storage;

  switch(((struct opGet *)msg)->opg_AttrID)
  {
    case ATTR(Aborted): *store = data->abort; return TRUE;
  }

  return DoSuperMethodA(cl, obj, msg);
}

///

/* Private Functions */

/* Public Methods */
/// DECLARE(Open)
// open find window
DECLARE(Open) // struct Folder *selectFolder
{
  GETDATA;
  struct Folder *selectFolder = msg->selectFolder;

  ENTER();

  // formerly a folder was marked to be searched in only if one was given
  // as this is quite unintuitive we now fall back to the current folder
  if(selectFolder == NULL && (struct MUI_NListtree_TreeNode *)xget(data->LT_FOLDERS, MUIA_NListtree_Active) == NULL)
    selectFolder = GetCurrentFolder();

  if(selectFolder != NULL)
  {
    struct MUI_NListtree_TreeNode *tn;
    int i=0;

    // now we have to walk through the nlisttree and find
    // the folder so that we can set it as active
    while((tn = (struct MUI_NListtree_TreeNode *)DoMethod(data->LT_FOLDERS, MUIM_NListtree_GetEntry, MUIV_NListtree_GetEntry_ListNode_Root, i, MUIF_NONE)) != NULL)
    {
      struct FolderNode *fnode = tn->tn_User;

      if(fnode->folder == selectFolder)
      {
        set(data->LT_FOLDERS, MUIA_NListtree_Active, tn);
        break;
      }

      i++;
    }
  }

  // check if the window is already open
  if(xget(obj, MUIA_Window_Open) == TRUE)
  {
    // bring window to front
    DoMethod(obj, MUIM_Window_ToFront);

    // make window active
    set(obj, MUIA_Window_Activate, TRUE);
  }
  else
  {
    SafeOpenWindow(obj);
  }

  // set object of the last search session as the active one again
  set(obj, MUIA_Window_ActiveObject, xget(data->GR_SEARCH, MUIA_SearchControlGroup_ActiveObject));

  RETURN(0);
  return 0;
}

///
/// DECLARE(Close)
// closes find window
DECLARE(Close)
{
  GETDATA;

  ENTER();

  // set the abort flag so that a running search will be stopped.
  if(data->active == TRUE)
  {
    data->abort = TRUE;
    data->clearOnEnd = TRUE;
  }

  // close the window. all the other stuff will be
  // disposed by the application as soon as it
  // disposes itself..
  set(obj, MUIA_Window_Open, FALSE);

  RETURN(0);
  return 0;
}

///
/// DECLARE(Search)
// start the search and shows progress
DECLARE(Search)
{
  GETDATA;
  ULONG numSelected;
  int fndmsg = 0;
  int totmsg = 0;
  int progress = 0;
  struct Folder **selectedFolders;

  ENTER();

  // by default we don't dispose on end
  data->clearOnEnd = FALSE;
  data->active = TRUE;
  data->abort = FALSE;

  set(obj, MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
  // disable some buttons while the search is going on
  DoMethod(obj, MUIM_MultiSet, MUIA_Disabled, TRUE, data->BT_SEARCH,
                                                    data->BT_SELECTACTIVE,
                                                    data->BT_SELECT,
                                                    data->BT_READ,
                                                    NULL);
  DoMethod(data->LV_MAILS, MUIM_NList_Clear);

  // start with forbidden immediate display of found mails, this greatly speeds
  // up the search process if many mails match the search criteria.
  set(data->LV_MAILS, MUIA_NList_Quiet, TRUE);

  DoMethod(data->LT_FOLDERS, MUIM_NListtree_Select, MUIV_NListtree_Select_All, MUIV_NListtree_Select_Ask, 0, &numSelected);
  if((selectedFolders = calloc(numSelected, sizeof(selectedFolders[0]))) != NULL)
  {
    struct MUI_NListtree_TreeNode *tn = (struct MUI_NListtree_TreeNode *)MUIV_NListtree_NextSelected_Start;
    ULONG i = 0;

    do
    {
      struct Folder *folder;

      DoMethod(data->LT_FOLDERS, MUIM_NListtree_NextSelected, &tn);
      if(tn == (struct MUI_NListtree_TreeNode *)MUIV_NListtree_NextSelected_End)
        break;

      if((folder = ((struct FolderNode *)tn->tn_User)->folder) != NULL)
      {
        if(MA_GetIndex(folder) == TRUE)
        {
          if(folder->Total != 0)
          {
            selectedFolders[i] = folder;
            totmsg += folder->Total;
            i++;
          }
          else
            numSelected--;
        }
        else
          numSelected--;
      }
      else
        numSelected--;
    }
    while(TRUE);

    if(totmsg != 0)
    {
      struct Search search;
      struct TimeVal last;

      // lets prepare the search
      DoMethod(data->GR_SEARCH, MUIM_SearchControlGroup_PrepareSearch, &search);

      // set the gauge
      snprintf(data->progressText, sizeof(data->progressText), tr(MSG_FI_GAUGETEXT), totmsg);
      xset(data->GA_PROGRESS, MUIA_Gauge_InfoText, data->progressText,
                              MUIA_Gauge_Max,      totmsg,
                              MUIA_Gauge_Current,  0);

      set(data->GR_PAGE, MUIA_Group_ActivePage, 1);

      memset(&last, 0, sizeof(struct TimeVal));

      for(i = 0; i < numSelected; i++)
      {
        struct Folder *folder = selectedFolders[i];
        struct MailList *folderMessages;

        if(MA_GetIndex(folder) == TRUE && (folderMessages = CloneMailList(folder->messages)) != NULL)
        {
          struct MailNode *mnode;

          // no need to lock the cloned list as it is private
          ForEachMailNode(folderMessages, mnode)
          {
            struct Mail *mail = mnode->mail;

            if(FI_DoSearch(&search, mail) == TRUE)
            {
              DoMethod(data->LV_MAILS, MUIM_NList_InsertSingle, mail, MUIV_NList_Insert_Sorted);
              fndmsg++;
            }

            // bail out if the search was aborted
            if(data->abort == TRUE)
              break;

            // increase the progress counter
            progress++;

            // then we update the gauge, but we take also care of not refreshing
            // it too often or otherwise it slows down the whole search process.
            if(TimeHasElapsed(&last, 250000) == TRUE)
            {
              // update the gauge
              set(data->GA_PROGRESS, MUIA_Gauge_Current, progress);
              // let the list show the found mails so far
              set(data->LV_MAILS, MUIA_NList_Quiet, FALSE);

              // handle the possibly received methods and messages
              CheckMethodStack();
              HandleThreads(TRUE);

              // signal the application to update now
              DoMethod(_app(obj), MUIM_Application_InputBuffered);

              // forbid immediate display again
              set(data->LV_MAILS, MUIA_NList_Quiet, TRUE);
            }
          }

          DeleteMailList(folderMessages);
        }

        // bail out if the search was aborted
        if(data->abort == TRUE)
          break;
      }

      // to let the gauge move to 100% lets increase it accordingly.
      set(data->GA_PROGRESS, MUIA_Gauge_Current, progress);

      // signal the application to update now
      DoMethod(_app(obj), MUIM_Application_InputBuffered);

      // free the temporary memory we allocated due to our
      // search operation
      FreeSearchData(&search);
    }

    free(selectedFolders);
  }

  set(data->LV_MAILS, MUIA_NList_Quiet, FALSE);
  set(data->GR_PAGE, MUIA_Group_ActivePage, 0);
  // enable the buttons again
  set(data->BT_SEARCH, MUIA_Disabled, FALSE);
  DoMethod(_app(obj), MUIM_MultiSet, MUIA_Disabled, fndmsg == 0, data->BT_SELECTACTIVE,
                                                                 data->BT_SELECT,
                                                                 data->BT_READ,
                                                                 NULL);

  data->active = FALSE;

  // if the closeHook has set the ClearOnEnd flag we have to clear
  // the result listview
  if(data->clearOnEnd == TRUE)
    DoMethod(data->LV_MAILS, MUIM_NList_Clear);
  else
    set(obj, MUIA_Window_ActiveObject, xget(data->GR_SEARCH, MUIA_SearchControlGroup_ActiveObject));

  RETURN(0);
  return 0;
}

///
/// DECLARE(Abort)
DECLARE(Abort)
{
  GETDATA;

  ENTER();

  data->abort = TRUE;

  RETURN(0);
  return 0;
}

///
/// DECLARE(CreateFilter)
// create a filter from the current search options
DECLARE(CreateFilter)
{
  GETDATA;
  int ch;
  char name[SIZE_NAME];

  ENTER();

  name[0] = '\0';

  // request a name for that new filter from the user
  if((ch = StringRequest(name, sizeof(name),
                               tr(MSG_FI_AddFilter),
                               tr(MSG_FI_AddFilterReq),
                               tr(MSG_Save),
                               tr(MSG_Use),
                               tr(MSG_Cancel), FALSE,
                               obj)) != 0)
  {
    struct FilterNode *filter;

    if((filter = CreateNewFilter(FA_TERMINATE, 0)) != NULL)
    {
      struct RuleNode *rule;

      strlcpy(filter->name, name, sizeof(filter->name));

      if((rule = GetFilterRule(filter, 0)) != NULL)
        DoMethod(data->GR_SEARCH, MUIM_SearchControlGroup_GUIToRule, rule);

      // Now add the new filter to our list
      AddTail((struct List *)&C->filterList, (struct Node *)filter);

      // check if we should immediately save our configuration or not
      if(ch == 1)
        SaveConfig(C, G->CO_PrefsFile, TRUE);
    }
  }

  RETURN(0);
  return 0;
}

///
/// DECLARE(SwitchFolder)
// sets active folder according to the selected message in the results window
DECLARE(SwitchFolder)
{
  GETDATA;
  struct Mail *mail;

  ENTER();

  // get the mail from the find list
  DoMethod(data->LV_MAILS, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &mail);
  if(mail != NULL)
  {
    LONG pos = MUIV_NList_GetPos_Start;

    // make sure the folder of the found mail is set active
    MA_ChangeFolder(mail->Folder, TRUE);

    // now get the position of the foundmail in the real mail list and set it active
    DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetPos, mail, &pos);

    // if we found the mail in the currently active listview
    // we make it the active one as well.
    if(pos != MUIV_NList_GetPos_End)
    {
      // Because the NList for the maillistview and the NList for the find listview
      // are sharing the same displayhook we have to call MUIA_NList_DisplayRecall
      // twice here so that it will recognize that something has changed or
      // otherwise both NLists will show glitches.
      xset(G->MA->GUI.PG_MAILLIST, MUIA_NList_DisplayRecall, TRUE,
                                   MUIA_NList_Active, pos);

      set(data->LV_MAILS, MUIA_NList_DisplayRecall, TRUE);
    }
  }

  RETURN(0);
  return 0;
}

///
/// DECLARE(ReadMail)
// open a read window for a message listed in the results window
DECLARE(ReadMail)
{
  GETDATA;
  struct Mail *mail;

  ENTER();

  DoMethod(data->LV_MAILS, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &mail);
  if(mail != NULL)
  {
    struct ReadMailData *rmData;

    if((rmData = CreateReadWindow(FALSE)) != NULL)
    {
      // make sure it is opened correctly and then read in a mail
      if(SafeOpenWindow(rmData->readWindow) == FALSE ||
         DoMethod(rmData->readWindow, MUIM_ReadWindow_ReadMail, mail) == FALSE)
      {
        // on any error we make sure to delete the read window
        // immediatly again.
        CleanupReadMailData(rmData, TRUE);
      }
    }
  }

  RETURN(0);
  return 0;
}

///
/// DECLARE(SelectMails)
// select matching messages in the main message list
DECLARE(SelectMails)
{
  GETDATA;
  struct Folder *folder;
  int i;

  ENTER();

  // unselect the currently selected mails first
  set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, MUIV_NList_Active_Off);
  DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL);

  folder = GetCurrentFolder();
  for(i=0; ;i++)
  {
    struct Mail *mail;

    DoMethod(data->LV_MAILS, MUIM_NList_GetEntry, i, &mail);
    if(mail == NULL)
      break;

    // only if the current folder is the same as this messages resides in
    if(mail->Folder == folder)
    {
      LONG pos = MUIV_NList_GetPos_Start;

      // get the position of the foundmail in the currently active
      // listview
      DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetPos, mail, &pos);

      // if we found the one in our listview we select it
      if(pos != MUIV_NList_GetPos_End)
        DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_Select, pos, MUIV_NList_Select_On, NULL);
    }
  }

  MA_ChangeSelected(TRUE);

  RETURN(0);
  return 0;
}

///
/// DECLARE(RemoveMail)
DECLARE(RemoveMail) // struct Mail *mail
{
  GETDATA;

  ENTER();

  DoMethod(data->LV_MAILS, MUIM_MainMailList_RemoveMail, msg->mail);

  RETURN(0);
  return 0;
}

///