root/SummaryView.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IMPLEMENT_DYNCREATE
  2. CSummaryView
  3. BEGIN_MESSAGE_MAP
  4. AssertValid
  5. Dump
  6. OnInitialUpdate
  7. OnGetdispinfo
  8. PreCreateWindow
  9. SetStack
  10. SetItem
  11. AddList
  12. OnChildNotify
  13. OnChar
  14. UpdateColumn
  15. SetStatus
  16. ClearStatus
  17. UnmarkStatus
  18. MarkDStatus
  19. SelectNext
  20. SelectPrev
  21. DeleteMail
  22. WriteList
  23. OnDblclk
  24. OnKeyDown
  25. OnSetFocus
  26. OnBegindrag
  27. SaveMail
  28. SaveMail
  29. PreTranslateMessage
  30. OnColumnclick
  31. QuickSortPartition
  32. QuickSortSwapStack
  33. QuickSort
  34. SetColumnOrderStatus
  35. ReBuildSummary
  36. OnLButtonUp
  37. OnRclick
  38. OnPopupDel
  39. OnPopupHeaderInfo
  40. OnPopupRawmailInfo
  41. OnPopupRebuild
  42. ClearAllMail
  43. MoveMail
  44. Clear
  45. GetSelectedMail

/*
 * Copyright (C) 2002-2003 chik, s.hiranaka
 * For license terms, see the file COPYING in this directory.
 */

// SummaryView.cpp : インプリメンテーション ファイル
//

#include "stdafx.h"
#include "Pochy.h"
#include "SummaryView.h"
#include "FolderView.h"
#include "MainFrm.h"
#include "CodeConvert.h"
#include "StrTok.h"
#include "MimeDecode.h"
#include "lib.h"
#include "direct.h"                     // _mkdir

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSummaryView

IMPLEMENT_DYNCREATE(CSummaryView, CListView)

CSummaryView::CSummaryView()
{
        this->m_stack_num = 0;
        this->m_status_changed = FALSE;
        this->m_index = -1;
}

CSummaryView::~CSummaryView()
{
        WriteList();
}

BEGIN_MESSAGE_MAP(CSummaryView, CListView)
        //{{AFX_MSG_MAP(CSummaryView)
        ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
        ON_WM_CHAR()
        ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
        ON_WM_KEYDOWN()
        ON_WM_SETFOCUS()
        ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
        ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
        ON_WM_LBUTTONUP()
        ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
        ON_COMMAND(ID_SUMMARYVIEW_DEL, OnPopupDel)
        ON_COMMAND(ID_SUMMARYVIEW_HEADER_INFO, OnPopupHeaderInfo)
        ON_COMMAND(ID_SUMMARYVIEW_RAWMAIL_INFO, OnPopupRawmailInfo)
        ON_COMMAND(ID_SUMMARYVIEW_REBUILD, OnPopupRebuild)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSummaryView 描画

void CSummaryView::OnDraw(CDC* pDC)
{
        CDocument* pDoc = GetDocument();
        // TODO: この位置に描画用のコードを追加してください
}

/////////////////////////////////////////////////////////////////////////////
// CSummaryView 診断

#ifdef _DEBUG
void CSummaryView::AssertValid() const
{
        CListView::AssertValid();
}

void CSummaryView::Dump(CDumpContext& dc) const
{
        CListView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSummaryView メッセージ ハンドラ

void CSummaryView::OnInitialUpdate() 
{
        CListCtrl& lc = GetListCtrl();
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        int i;
        CString num;
        char* Column[] = { "状態", "サイズ", "件名", "差出人", "日付" };
        LV_COLUMN lvc;
        DWORD dwStyle;
        HWND hWnd;

        // 現在のスタイルから、レポートスタイルへ変更
        hWnd = lc.GetSafeHwnd();
        dwStyle = GetWindowLong(hWnd, GWL_STYLE);
        SetWindowLong(hWnd, GWL_STYLE, (dwStyle &~ LVS_TYPEMASK) | LVS_REPORT);
        lc.SetExtendedStyle(LVS_EX_FULLROWSELECT);

        // 色の設定
        COLORREF m_colorEdit;
        // 背景色
        m_colorEdit = RGB(
                app->GetProfileInt("SummaryViewColor", "BkColorR", 0),
                app->GetProfileInt("SummaryViewColor", "BkColorG", 0),
                app->GetProfileInt("SummaryViewColor", "BkColorB", 0));
        lc.SetBkColor(m_colorEdit);
        // テキストの背景色
        m_colorEdit = RGB(
                app->GetProfileInt("SummaryViewColor", "BkColorR", DEF_BKG_COLOR_R),
                app->GetProfileInt("SummaryViewColor", "BkColorG", DEF_BKG_COLOR_G),
                app->GetProfileInt("SummaryViewColor", "BkColorB", DEF_BKG_COLOR_B));
        lc.SetTextBkColor(m_colorEdit);
        // 文字の色
        m_colorEdit = RGB(
                app->GetProfileInt("SummaryViewColor", "TxtColorR", DEF_TXT_COLOR_R),
                app->GetProfileInt("SummaryViewColor", "TxtColorG", DEF_TXT_COLOR_G),
                app->GetProfileInt("SummaryViewColor", "TxtColorB", DEF_TXT_COLOR_B));
        lc.SetTextColor(m_colorEdit);

        // リストビューへカラムを設定
        lvc.mask = LVCF_FMT|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
        lvc.fmt = LVCFMT_LEFT;
        for(i = 0; i < 5; i++){
                lvc.pszText = Column[i];
                num.Format("%d", i);
                lvc.cx = app->GetProfileInt("SummaryViewColumn", num.GetBuffer(0), 100);
                if(lvc.cx > 1000){
                        lvc.cx = 100;
                }
                lc.InsertColumn(i, &lvc);
        }

        // リストビューへデータを格納する
        m_index = -1;
}

void CSummaryView::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) 
{
        LV_DISPINFO *pDispInfo = (LV_DISPINFO*)pNMHDR;

        int num = pDispInfo->item.iItem;
        char *buf;

        if(pDispInfo->item.mask & LVIF_TEXT){
                switch(pDispInfo->item.iSubItem){
                        case 0:
                                buf = m_array_list[m_stack_num-num-1].m_str6.GetBuffer(0);
                                lstrcpy(pDispInfo->item.pszText, buf);
                                break;
                        case 1:
                                buf = m_array_list[m_stack_num-num-1].m_str1.GetBuffer(0);
                                lstrcpy(pDispInfo->item.pszText, buf);
                                break;                                  
                        case 2:
                                buf = m_array_list[m_stack_num-num-1].m_str2.GetBuffer(0);
                                lstrcpy(pDispInfo->item.pszText, buf);
                                break;                                  
                        case 3:
                                buf = m_array_list[m_stack_num-num-1].m_str3.GetBuffer(0);
                                lstrcpy(pDispInfo->item.pszText, buf);
                                break;
                        case 4:
                                buf = m_array_list[m_stack_num-num-1].m_str4.GetBuffer(0);
                                lstrcpy(pDispInfo->item.pszText, buf);
                                break;
                }
        }
        *pResult = 0;   
}

BOOL CSummaryView::PreCreateWindow(CREATESTRUCT& cs) 
{

        // ListViewをownerdataに変更→高速に表示されるようになる
        // SetItemCountExを実行することで、OnGetdispinfoが呼ばれる
        cs.style        |= LVS_OWNERDATA 
                                | LVS_REPORT 
                                /*| LVS_SINGLESEL*/ 
                                | LVS_SHOWSELALWAYS;
        // LVS_SORTDESCENDING  LVS_SORTASCENDING

        return CListView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CSummaryView メッセージ ハンドラでない関数

int CSummaryView::SetStack(CString path)
{
        CString tmp;
        CString message;
        SLISTSTACK list;
        CStrTok StrTok;

        CStdioFile ReadFile;
        if(!ReadFile.Open(path+"\\list", CFile::modeRead | CFile::typeText)){
#if 0 // listがない場合はつくるようにする
                message.Format("CSummaryView: cannot open %s\\list", path.GetBuffer(0));
                AfxMessageBox(message.GetBuffer(0));
                return -1;
#else
//              CString NullBuf;
//              NullBuf.Empty();
                g_fcreate(path+"\\list");
                if(!ReadFile.Open(path+"\\list", CFile::modeRead | CFile::typeText)){
                        message.Format("CSummaryView: cannot open %s\\list", path.GetBuffer(0));
                        AfxMessageBox(message.GetBuffer(0));
                        return -1;
                }
#endif
        }
        // ArrayListに代入
        m_array_list.RemoveAll();
        int n=0;
        while(ReadFile.ReadString(tmp)){
                for(int i=1; i<9; i++){
                        switch(i){
                                case 1:
                                        list.m_str1 = StrTok.Tokenize(tmp.GetBuffer(0), "\x02");
                                        break;
                                case 2:
                                        list.m_str2 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                                case 3:
                                        list.m_str3 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                                case 4:
                                        list.m_str4 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                                case 5:
                                        list.m_str5 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                                case 6:
                                        list.m_str6 = StrTok.Tokenize(NULL, "\x02");
                                        if(-1 != list.m_str6.Find("N")){
                                                m_unread++;
                                        }
                                        break;
                                case 7:
                                        list.m_str7 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                                case 8:
                                        list.m_str8 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                                case 9:
                                        list.m_str9 = StrTok.Tokenize(NULL, "\x02");
                                        break;
                        }
                }
                n++;
                m_array_list.Add(list);
                tmp.Empty();
        }
        ReadFile.Close();
        return(n);
}

void CSummaryView::SetItem(CString path)
{
        WriteList(); // 取り合えず現在の内容をlistに保存
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)this->GetParentFrame();
        CListCtrl& lc = GetListCtrl();
        lc.DeleteAllItems();
        m_path = path; // 現在表示しようとしているlistファイルのあるフォルダのパスをm_pathに保存
        m_unread = 0;

        CString current_account = mf->m_pAcntV->GetCurrentAccountName();

        // リストビューのカラムの幅をiniファイルへ保存
        CString num;
        for(int i = 0; i < 5; i++){
                num.Format("%d", i);
                app->WriteProfileInt("SummaryViewColumn", num.GetBuffer(0), lc.GetColumnWidth(i));
        }

        // listviewのコラムを必要に応じて変更する
        if(path == app->m_app_path+"\\"+current_account+"\\outbox"
                || path == app->m_app_path+"\\"+current_account+"\\draft")
                this->UpdateColumn(SMRY_COLUMN_TO);
        else
                this->UpdateColumn(SMRY_COLUMN_FROM);

        m_stack_num = SetStack(path);

        CString unread;
        unread.Format("未読 %d  メール数 %d", m_unread, m_stack_num);
        mf->SetStatusBarText(2, unread);

        m_index = -1; // 何も選択されていない状態
        if(m_stack_num != -1)
                lc.SetItemCountEx(m_stack_num, LVSICF_NOSCROLL); // これでOnGetDispinfoが呼ばれる
}

void CSummaryView::AddList(SLISTSTACK *pList)
{
        CListCtrl& lc = GetListCtrl();
        m_stack_num++;
        m_array_list.Add(*pList);
        lc.InsertItem(0, pList->m_str1.GetBuffer(0)); // オーナードローなのでサブアイテムはOnGetdispinfoで処理される
        if(m_index != -1)
                m_index++;
}

BOOL CSummaryView::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
        if(message == WM_NOTIFY){
                NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lParam;

                // 別のアイテムが選択された後に呼ばれる
                if( pNMListView->hdr.code == LVN_ITEMCHANGED && pNMListView->uNewState == 3 &&
                        m_index != pNMListView->iItem )
                {
                        CPochyApp* app = (CPochyApp*)AfxGetApp();
                        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
                        CTextView *tv = (CTextView*)mf->m_pTextV;
                        CFolderView *fv = (CFolderView *)mf->m_pTreeV;
                        CAccountView *av = (CAccountView*)mf->m_pAcntV;
                        m_index = pNMListView->iItem;

                        BOOL b = ClearStatus(m_index);
                        m_status_changed |= b;
                        if(b){
                                CString unread;
                                unread.Format("未読 %d  メール数 %d", --m_unread, m_stack_num);
                                mf->SetStatusBarText(2, unread);
                        }

                        // mainframeの各ボタンを有効にする
                        mf->m_button_reply = TRUE;
                        mf->m_button_transfer = TRUE;
                        mf->m_button_info = TRUE;

                        tv->Update(m_path + "\\" + m_array_list[m_stack_num-m_index-1].m_str5);

                        *pLResult = 0;
                }
        }
        return CListView::OnChildNotify(message, wParam, lParam, pLResult);
}

void CSummaryView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
        int i;
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CFolderView *fv = (CFolderView *)mf->m_pTreeV;
        CStringArray cstra;
        CUIntArray ia;

        CString current_account = mf->m_pAcntV->GetCurrentAccountName();

        if(mf->Char(nChar))
                return;

        switch(nChar){
        case 'd':
                if(this->m_index != -1){
                        this->m_status_changed |= this->MarkDStatus(m_index);
                        this->SelectNext();
                }
                break;
        case 'u':
                if(this->m_index != -1){
                        this->m_status_changed |= UnmarkStatus(m_index);
                        this->SelectNext();
                }
                break;
        case 'x':
                for(i=0; i < this->m_array_list.GetSize(); i++){
                        if(this->m_array_list.GetAt(i).m_str6.Find("D") != -1){
                                ia.Add(i);
                        }
                }
                if(fv->GetSelectedItemKind() != FV_TRASH){
                        this->MoveMail(ia, app->m_app_path+"\\"+current_account+"\\trash", SMRY_COLUMN_FROM);
                }else{
                        CString null;
                        null.Empty();
                        this->MoveMail(ia, null, SMRY_COLUMN_FROM);
                }
                break;
        case '<':
                this->GetListCtrl().SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
                this->GetListCtrl().EnsureVisible(0, TRUE);
                break;
        case '>':
                this->GetListCtrl().SetItemState(this->m_stack_num-1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
                this->GetListCtrl().EnsureVisible(this->m_stack_num-1, TRUE);
                break;
        default:
                break;
        }
}

void CSummaryView::UpdateColumn(int flag)
{
        CListCtrl& lc = this->GetListCtrl();
        CPochyApp *app = (CPochyApp *)AfxGetApp();

        CString num;
        LV_COLUMN lvc;
        char* Column1[] = { "状態", "サイズ", "件名", "差出人", "日付" };
        char* Column2[] = { "状態", "サイズ", "件名", "宛先", "日付" };

        lvc.mask = LVCF_FMT|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM;
        lvc.fmt = LVCFMT_LEFT;

        int i;
        for(i = 0; i < 5; i++) lc.DeleteColumn(0);

        if(flag == SMRY_COLUMN_FROM){
                for(i = 0; i < 5; i++){
                        lvc.pszText = Column1[i];
                        num.Format("%d", i);
                        lvc.cx = app->GetProfileInt("SummaryViewColumn", num.GetBuffer(0), 100);
                        lc.InsertColumn(i, &lvc);
                }
        }
        if(flag == SMRY_COLUMN_TO){
                for(i = 0; i < 5; i++){
                        lvc.pszText = Column2[i];
                        num.Format("%d", i);
                        lvc.cx = app->GetProfileInt("SummaryViewColumn", num.GetBuffer(0), 100);
                        lc.InsertColumn(i, &lvc);
                }
        }

        int status = GetPrivateProfileInt("list", "order", 0, this->m_path+"\\folder.ini");
        this->SetColumnOrderStatus(status);
}

void CSummaryView::SetStatus(int nItem, CString status)
{
        if(this->m_index > -1 && this->m_index < m_stack_num){
                this->m_array_list[this->m_stack_num-nItem-1].m_str6 = status;
                this->GetListCtrl().RedrawItems(nItem,nItem);
        }
}

BOOL CSummaryView::ClearStatus(int nItem)
{
        CString buf;
        buf = this->m_array_list.GetAt(this->m_stack_num-nItem-1).m_str6;
        if(buf.Left(1)=="N"){
                SetStatus(nItem, " "+buf.Right(1));
                return TRUE;
        }
        return FALSE;
}

BOOL CSummaryView::UnmarkStatus(int nItem)
{
        CString buf;
        buf = this->m_array_list.GetAt(this->m_stack_num-nItem-1).m_str6;
        if(buf.Left(1)=="D"){
                this->SetStatus(nItem, " "+buf.Right(1));
                return TRUE;
        }
        return FALSE;
}

BOOL CSummaryView::MarkDStatus(int nItem)
{
        CString buf;
        buf = this->m_array_list.GetAt(this->m_stack_num-nItem-1).m_str6;
        if(buf.Left(1)!="D"){
                this->SetStatus(nItem, "D"+buf.Right(1));
                return TRUE;
        }
        return FALSE;
}

void CSummaryView::SelectNext()
{
        if(this->m_index < m_stack_num -1){
                this->GetListCtrl().SetItemState(this->m_index+1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
                this->GetListCtrl().EnsureVisible(this->m_index, TRUE);
                this->GetListCtrl().RedrawItems(this->m_index, this->m_index);
                this->UpdateWindow();
        }
}

void CSummaryView::SelectPrev()
{
        if(this->m_index > 0){
                this->GetListCtrl().SetItemState(this->m_index-1,LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
                this->GetListCtrl().EnsureVisible(this->m_index, TRUE);
                this->GetListCtrl().RedrawItems(this->m_index, this->m_index);
                this->UpdateWindow();
        }
}

void CSummaryView::DeleteMail(CUIntArray &index_array)
{
        if(index_array.GetSize() < 1){
                return;
        }

        CWaitCursor wait_cursor; // turn cursor into sandglass

        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CTextView *tv = (CTextView *)mf->m_pTextV;
        CStringArray cstra;

        int i = index_array.GetSize()-1;
        while(i >= 0){
                DeleteFile(m_path+"\\"+m_array_list.GetAt(m_stack_num-index_array.GetAt(i)-1).m_str5);
                this->m_array_list.RemoveAt(m_stack_num-index_array.GetAt(i)-1);
                this->m_stack_num--;
                i--;
        }
        // something is changed.
        this->GetListCtrl().DeleteAllItems();
        this->m_index = -1;
        this->GetListCtrl().SetItemCountEx(m_stack_num, LVSICF_NOSCROLL);
        this->m_status_changed = TRUE;
        this->WriteList();
        tv->Clear();
}

void CSummaryView::WriteList()
{
        if(!m_status_changed)
                return;
        this->m_status_changed = FALSE;

        FILE *file;
        if(!(file = fopen(m_path + "\\list", "wb"))){
                AfxMessageBox("error: fopen in WriteList()");
                return;
        }
        CWaitCursor wait_cursor; // turn cursor into sandglass
        CString str;
        for(int i=0;i<this->m_array_list.GetSize();i++){
                str =           m_array_list.GetAt(i).m_str1;
                str += "\x02" + m_array_list.GetAt(i).m_str2;
                str += "\x02" + m_array_list.GetAt(i).m_str3;
                str += "\x02" + m_array_list.GetAt(i).m_str4;
                str += "\x02" + m_array_list.GetAt(i).m_str5;
                str += "\x02" + m_array_list.GetAt(i).m_str6;
                str += "\x02" + m_array_list.GetAt(i).m_str7;
                str += "\x02" + m_array_list.GetAt(i).m_str8;
                str += "\x02" + m_array_list.GetAt(i).m_str9;
                str += "\r\n";
                fwrite(str, sizeof(char),str.GetLength(),file);
        }
        fclose(file);
}

void CSummaryView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
{
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CFolderView *fv = (CFolderView*)mf->m_pTreeV;

        POSITION Pos = this->GetListCtrl().GetFirstSelectedItemPosition();
        int index = (int)Pos-1;

        if((fv->GetSelectedItemKind() == FV_DRAFT ||
                fv->GetSelectedItemKind() == FV_OUTBOX) &&
                index != -1)
        {
                CMimeDecode md;
                if(!md.DoIt(m_path + "\\" + this->m_array_list[m_stack_num-index-1].m_str5)){
                        return;
                }

                app->m_me.Initialize();
                app->m_me.SetTo(md.m_hi.GetTo());
                app->m_me.SetCc(md.m_hi.GetCc());
                app->m_me.SetBcc(md.m_hi.GetBcc());
                app->m_me.SetFrom(md.m_hi.GetFrom());
                app->m_me.SetSubject(md.m_hi.GetSubject());
                app->m_me.SetReplyTo(md.m_hi.GetReplyTo());
                app->m_me.SetMessageID(md.m_hi.GetMsgID());
                app->m_me.SetInReplyTo(md.m_hi.GetInReplyTo());
                if(md.IsPgpMime())
                        app->m_me.SetMode(ME_MODE_PGP);
                else
                        app->m_me.SetMode(ME_MODE_NONE);

                MULTIPART_STRUCT2 data;
                int i=0;
                while(i < md.HowManyPart()){
                        CStringArray body;
                        data.m_content_type = md.GetRawCT(i);
                        data.m_content_transfer_encoding = md.GetRawCTE(i);
                        data.m_content_disposition = md.GetRawCD(i);
                        md.GetBody(i, body);
                        g_cstra2cstr(body, data.m_body, g_cstra_getsize(body));
                        data.m_encoding_type = md.GetEncodingType(i);
                        data.m_file_name = md.GetFileName(i);
                        data.m_type = md.GetContentType(i);
                        app->m_me.AddMultipart(data);
                        i++;
                }
                if(fv->GetSelectedItemKind() == FV_DRAFT){
                        CUIntArray ia;
                        this->GetSelectedMail(ia);
                        this->DeleteMail(ia);
                }
                app->CreateDraftFrame(mf->m_pAcntV->GetCurrentAccountName());
        }
        *pResult = 0;
}

void CSummaryView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CFolderView *fv = (CFolderView *)mf->m_pTreeV;
        CStringArray cstra;
        CString message;
        CUIntArray ia;

        CString current_account = mf->m_pAcntV->GetCurrentAccountName();

        switch(nChar){
                case 46: // if press del key, delete mail
                        this->GetSelectedMail(ia);
                        if(this->m_index == -1){
                                return;
                        }
                        if(fv->GetSelectedItemKind() != FV_TRASH){
                                if(ia.GetSize() == 1){
                                        message = this->m_array_list[this->m_stack_num-this->m_index-1].m_str2+"\r\n\r\ntrashに移してもよいですか?";
                                }else if(ia.GetSize() > 1){
                                        message = "\r\n\r\ntrashに移してもよいですか?";
                                }
                                if(IDYES == AfxMessageBox(message, MB_YESNO)){
                                        this->MoveMail(ia, app->m_app_path+"\\"+current_account+"\\trash", SMRY_COLUMN_FROM);
                                }
                        }else{
                                if(ia.GetSize() == 1){
                                        message = this->m_array_list[this->m_stack_num-this->m_index-1].m_str2+"\r\n\r\n削除してもよいですか?";
                                }else if(ia.GetSize() > 1){
                                        message = "\r\n\r\n削除してもよいですか?";
                                }
                                if(IDYES == AfxMessageBox(message, MB_YESNO)){
                                        this->DeleteMail(ia);
                                }
                        }
                        break;
                default:
                        break;
        }
        CListView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CSummaryView::OnSetFocus(CWnd* pOldWnd) 
{
        CListView::OnSetFocus(pOldWnd);
}

void CSummaryView::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
        NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
        CUIntArray ia;

        CListCtrl &lc = GetListCtrl();
        CPochyApp* app = (CPochyApp*)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CFolderView* fv = mf->m_pTreeV;
        fv->m_ListItemDrag = pNMListView->iItem;
        fv->m_hitemDrag = NULL;

        POINT pt;
        pt.x = pt.y = 8;
        this->GetSelectedMail(ia);
        if(ia.GetSize() > 1){
                fv->m_drag_image.BeginDrag(1, CPoint(8, 8));
        }else{
                fv->m_drag_image.BeginDrag(0, CPoint(8, 8));
        }
        pt = pNMListView->ptAction;
        ClientToScreen(&pt);
        fv->m_drag_image.DragEnter(NULL, pt);

        fv->m_bLDragging = TRUE;
        fv->m_hitemDrop = NULL;
        fv->SetCapture();

        *pResult = 0;
}

BOOL CSummaryView::SaveMail(CString path, CString mail, int mail_status, int what_kind_box)
{
        if(path.IsEmpty()){
                return FALSE;
        }

        CString header;
        CString list;
        CString subject;
        CString to;
        CString from;
        CString date;
        CString seq;
        CString size;
        CString buf;
        CString stat;
        CString message_id;
        CString in_reply_to;
        CString char_set;
        int num;

        SLISTSTACK data;

        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame *)app->m_pMainWnd;

        num = g_get_min_num(path);
        // CStringにseq番号をセットする(メール保存用)
        seq.Format("%d", num);

        // メールの保存
        CCodeConvert cc(mail);
        mail = cc.ToJis();
        g_cstring2file(mail, path + "\\" + seq);

        // メールサイズの取得(必ずメールを保存した後に)
        size.Format("%d", g_getfs(path + "\\" + seq));

        // メールからヘッダだけ抜き出してdecodeし必要なヘッダ情報を取得する
        CHeaderInfo hi;
        CStringArray cstra;
        header = mail.Left(mail.Find("\r\n\r\n")+2);
        g_cstr2cstra(header, cstra,"\r\n");
        hi.DoIt(cstra);

        subject = hi.GetSubject();
        subject.Remove('\r');
        subject.Remove('\n');

        to = hi.GetTo();
        to.Remove('\r');
        to.Remove('\n');

        from = hi.GetFrom();
        from.Remove('\r');
        from.Remove('\n');

        message_id = hi.GetMsgID();
        message_id.Remove('\r');
        message_id.Remove('\n');

        in_reply_to = hi.GetInReplyTo();
        in_reply_to.Remove('\r');
        in_reply_to.Remove('\n');

        char_set = hi.GetCharset();
        char_set.Remove('\r');
        char_set.Remove('\n');

        date = hi.GetDate();

        // dateを持たないメールの場合
        if(date.IsEmpty()){
                CTime t = CTime::GetCurrentTime();
                date.Format("%02d/%02d/%d %02d:%02d:%02d",
                        t.GetYear(),
                        t.GetMonth(),
                        t.GetDay(),
                        t.GetHour(),
                        t.GetMinute(),
                        t.GetSecond());
        }

        // statの設定
        if(hi.GetBoundary().IsEmpty() && mail_status == SMRY_STATUS_NEW)
                stat = "N ";
        else if(!hi.GetBoundary().IsEmpty() && mail_status == SMRY_STATUS_NONE)
                stat = " M";
        else if(hi.GetBoundary().IsEmpty() && mail_status == SMRY_STATUS_NONE)
                stat = "  ";
        else
                stat = "NM";

        // listの設定
        list += size;
        list += "\x02";
        list += subject;
        list += "\x02";
        // 保存先によってサマリーに表示される情報が違うため
        if(what_kind_box == SMRY_COLUMN_TO)
                list += to;
        else
                list += from;
        list += "\x02";
        list += date;
        list += "\x02";
        list += seq;
        list += "\x02";
        list += stat;
        list += "\x02";
        list += message_id;
        list += "\x02";
        list += in_reply_to;
        list += "\x02";
        list += char_set;
        list += "\r\n";

        // listviewのためのデータを保存
        CStdioFile Write2List;
        if(!Write2List.Open(path + "\\list", 
                CFile::modeCreate
                |CFile::modeNoTruncate
                |CFile::modeWrite
                |CFile::typeBinary))
        {
                AfxMessageBox("CStdioFile: error cannot open list file");
                return FALSE;
        }
        Write2List.SeekToEnd();
        Write2List.WriteString(list);
        Write2List.Close();

        data.m_str1 = size;
        data.m_str2 = subject;
        // 保存先によってサマリーに表示される情報が違うため
        if(what_kind_box == SMRY_COLUMN_TO)
                data.m_str3 = to;
        else
                data.m_str3 = from;
        data.m_str4 = date;
        data.m_str5 = seq;
        data.m_str6 = stat;
        data.m_str7 = message_id;
        data.m_str8 = in_reply_to;
        data.m_str9 = char_set;

        // 保存先が現在表示されているフォルダなら以下を実行
        if(m_path == path){
                AddList(&data);
                if(m_index != -1){
                        m_index++;
                }
                // 未読メールの数m_unreadを++する
                if(stat.Find("N") != -1){
                        CString unread;
                        unread.Format("未読 %d  メール数 %d", ++m_unread, m_stack_num);
                        mf->SetStatusBarText(2, unread);
                }
        }
        return TRUE;
}

BOOL CSummaryView::SaveMail(CString path, CStringArray &mail, int mail_status, int what_kind_box)
{
        if(path.IsEmpty()){
                return FALSE;
        }

        CString header;
        CString list;
        CString subject;
        CString to;
        CString from;
        CString date;
        CString seq;
        CString size;
        CString buf;
        CString stat;
        CString message_id;
        CString in_reply_to;
        CString char_set;
        int num;

        SLISTSTACK data;

        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame *)app->m_pMainWnd;

        // seeking for minimum num. this is used as name of file when mail is saved. MH?
        num = g_get_min_num(path);
        seq.Format("%d", num);

        // saving mail in MH format ? is this MH format or not, I don't know precisely.
        g_cstra2file(path + "\\" + seq, mail);
        // getting size of mail (this must be done after saving mail)
        size.Format("%d", g_getfs(path + "\\" + seq));

        // decoding mail and getting neccesary information.
        CHeaderInfo hi;
        hi.DoIt(mail);
        subject = hi.GetSubject();
        subject.Remove('\r');
        subject.Remove('\n');
        to = hi.GetTo();
        to.Remove('\r');
        to.Remove('\n');
        from = hi.GetFrom();
        from.Remove('\r');
        from.Remove('\n');
        message_id = hi.GetMsgID();
        message_id.Remove('\r');
        message_id.Remove('\n');
        in_reply_to = hi.GetInReplyTo();
        in_reply_to.Remove('\r');
        in_reply_to.Remove('\n');
        char_set = hi.GetCharset();
        char_set.Remove('\r');
        char_set.Remove('\n');
        date = hi.GetDate();

        // if mail don't have any information about DATE, below is done.
        if(date.IsEmpty()){
                CTime t = CTime::GetCurrentTime();
                date.Format("%02d/%02d/%02d %02d:%02d:%02d",
                        t.GetYear(),
                        t.GetMonth(),
                        t.GetDay(),
                        t.GetHour(),
                        t.GetMinute(),
                        t.GetSecond());
        }

        // set current status to stat.
        if(hi.GetBoundary().IsEmpty() && mail_status == SMRY_STATUS_NEW)
                stat = "N ";
        else if(!hi.GetBoundary().IsEmpty() && mail_status == SMRY_STATUS_NONE)
                stat = " M";
        else if(hi.GetBoundary().IsEmpty() && mail_status == SMRY_STATUS_NONE)
                stat = "  ";
        else
                stat = "NM";

        // setting content of cummaryview into list.
        list += size;
        list += "\x02";
        list += subject;
        list += "\x02";
        // content of summaryview is changable up to which folder is seleceted.
        // especialy, outbox is selected, summaryview display [To] address instead of [From] address.
        if(what_kind_box == SMRY_COLUMN_TO)
                list += to;
        else
                list += from;
        list += "\x02";
        list += date;
        list += "\x02";
        list += seq;
        list += "\x02";
        list += stat;
        list += "\x02";
        list += message_id;
        list += "\x02";
        list += in_reply_to;
        list += "\x02";
        list += char_set;
        list += "\r\n";

        // saving data for summaryview.
        CStdioFile Write2List;
        if(!Write2List.Open(path + "\\list", 
                CFile::modeCreate
                |CFile::modeNoTruncate
                |CFile::modeWrite
                |CFile::typeBinary))
        {
                AfxMessageBox("CStdioFile: error cannot open list file");
                return FALSE;
        }
        Write2List.SeekToEnd();
        Write2List.WriteString(list);
        Write2List.Close();

        data.m_str1 = size;
        data.m_str2 = subject;
        // content of summaryview is changing up to which folder is selected in folderview.
        // if outbox is selected, summaryview display [To] address instead of [From].
        // if other box but outbox is selected, viceversa.
        if(what_kind_box == SMRY_COLUMN_TO)
                data.m_str3 = to;
        else
                data.m_str3 = from;
        data.m_str4 = date;
        data.m_str5 = seq;
        data.m_str6 = stat;
        data.m_str7 = message_id;
        data.m_str8 = in_reply_to;
        data.m_str9 = char_set;

        // if saving to current displayed folder, need to increment m_index. 
        // m_index is variable of current selected item number.
        if(m_path == path){
                AddList(&data);
                if(m_index != -1){
                        m_index++;
                }

                // number of unreaded mail is incremented
                if(stat.Find("N") != -1){
                        CString unread;
                        unread.Format("未読 %d  メール数 %d", ++m_unread, m_stack_num);
                        mf->SetStatusBarText(2, unread);
                }
        }
        return TRUE;
}

BOOL CSummaryView::PreTranslateMessage(MSG* pMsg)
{
        if(pMsg->message == WM_KEYDOWN){
                if(pMsg->wParam == 78){ // pressing [n] is same as [PgDn].
                        pMsg->wParam = 40;
                }
                else if(pMsg->wParam == 80){ // pressing [p] is same as [PgUp].
                        pMsg->wParam = 38;
                }
        }
        return CListView::PreTranslateMessage(pMsg);
}

// quick sort, is not completed. this cannot work very fast.
void CSummaryView::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) 
{
        if(m_stack_num == 0) return;

        CPochyApp* app = (CPochyApp*)AfxGetApp();
        NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
        CWaitCursor wait_cursor;

        // get current message status from folder.ini
        int order;
        int num = GetPrivateProfileInt("list", "order", 0, m_path+"\\folder.ini");

        // change colum message depending on message order
        if(num/10 == pNMListView->iSubItem){
                switch(num%10){
                case 0:
                        num = pNMListView->iSubItem*10+1;
                        order = 1;
                        break;
                case 1:
                        num = pNMListView->iSubItem*10+2;
                        order = 2;
                        break;
                case 2:
                        num = pNMListView->iSubItem*10;
                        order = 0;
                        break;
                }
        }else{
                num = pNMListView->iSubItem*10+1;
                order = 1;
        }
        this->SetColumnOrderStatus(num);

        // save current message order status to folder.ini
        CString buf;
        buf.Format("%d", num);
        WritePrivateProfileString("list", "order", buf, m_path+"\\folder.ini");

        // start quicksort
        switch(pNMListView->iSubItem){
        case 0:
                m_status_changed = TRUE;
                this->QuickSort(0, m_array_list.GetUpperBound(), 0, order);
                break;
        case 1:
                m_status_changed = TRUE;
                this->QuickSort(1, m_array_list.GetUpperBound(), 1, order);
                break;
        case 2:
                m_status_changed = TRUE;
                this->QuickSort(0, m_array_list.GetUpperBound(), 2, order);
                break;
        case 3:
                m_status_changed = TRUE;
                this->QuickSort(0, m_array_list.GetUpperBound(), 3, order);
                break;
        case 4:
                m_status_changed = TRUE;
                this->QuickSort(0, m_array_list.GetUpperBound(), 4, order);
                break;
        }

        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CTextView *tv =(CTextView*)mf->m_pTextV;
        CListCtrl &lc = GetListCtrl();

        m_index = -1;
        lc.DeleteAllItems();
        tv->SetWindowText("");
        mf->HideMultiPartView(TRUE);
        lc.SetItemCountEx(m_stack_num, LVSICF_NOSCROLL);

        *pResult = 0;
}

// below is implementation of quick sort, fuckin dirty code, need to be modified later.
int CSummaryView::QuickSortPartition(int start, int end, int item_num, int order)
{
        int i, j, k;
        CString pivot;
        CString buf1;
        CString buf2;

        i = start;
        j = end;
        k = (end+start)/2;
        this->QuickSortSwapStack(k, end);

        if(order != 0){
                switch(item_num){
                case 0:
                        if(order == 1){
                                pivot = m_array_list.GetAt(end).m_str6+m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str6+m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) < 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str6+m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) > 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }else if(order == 2){
                                pivot = m_array_list.GetAt(end).m_str6+m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str6+m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) > 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str6+m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) < 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }
                        break;
                case 1:
                        int c;
                        c = atoi(m_array_list.GetAt(end).m_str1);
                        if(order == 1){
                                for(;;){
                                        while(i<j){
                                                if(c < atoi(m_array_list.GetAt(i).m_str1))
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                if(c > atoi(m_array_list.GetAt(j).m_str1))
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }else if(order == 2){
                                for(;;){
                                        while(i<j){
                                                if(c > atoi(m_array_list.GetAt(i).m_str1))
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                if(c < atoi(m_array_list.GetAt(j).m_str1))
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }
                        break;
                case 2:
                        if(order == 1){
                                pivot = m_array_list.GetAt(end).m_str2+m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str2+m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) < 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str2+m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) > 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }else if(order == 2){
                                pivot = m_array_list.GetAt(end).m_str2+m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str2+m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) > 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str2+m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) < 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }
                        break;
                case 3:
                        if(order == 1){
                                pivot = m_array_list.GetAt(end).m_str3+m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str3+m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) < 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str3+m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) > 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }else if(order == 2){
                                pivot = m_array_list.GetAt(end).m_str3+m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str3+m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) > 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str3+m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) < 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }
                        break;
                case 4:
                        if(order == 1){
                                pivot = m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) < 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) > 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }else if(order == 2){
                                pivot = m_array_list.GetAt(end).m_str4;
                                for(;;){
                                        while(i<j){
                                                buf1 = m_array_list.GetAt(i).m_str4;
                                                if(_stricmp(buf1, pivot) > 0)
                                                        break;
                                                i++;
                                        }
                                        while(i<j){
                                                buf2 = m_array_list.GetAt(j).m_str4;
                                                if(_stricmp(buf2, pivot) < 0)
                                                        break;
                                                j--;
                                        }
                                        if(i >= j)
                                                break;
                                        this->QuickSortSwapStack(i, j);
                                }
                        }
                        break;
                }
        }else if(order == 0){
                int c;
                c = atoi(m_array_list.GetAt(end).m_str5);
                for(;;){
                        while(i<j){
                                if(c < atoi(m_array_list.GetAt(i).m_str5))
                                        break;
                                i++;
                        }
                        while(i<j){
                                if(c > atoi(m_array_list.GetAt(j).m_str5))
                                        break;
                                j--;
                        }
                        if(i >= j)
                                break;
                        this->QuickSortSwapStack(i, j);
                }
        }

        this->QuickSortSwapStack(i, end);
        return i;
}

// swap all member of SLISTSTACK one another.
void CSummaryView::QuickSortSwapStack(int i, int j)
{
        SLISTSTACK tmp;

        tmp.m_str1 = m_array_list.GetAt(i).m_str1;
        tmp.m_str2 = m_array_list.GetAt(i).m_str2;
        tmp.m_str3 = m_array_list.GetAt(i).m_str3;
        tmp.m_str4 = m_array_list.GetAt(i).m_str4;
        tmp.m_str5 = m_array_list.GetAt(i).m_str5;
        tmp.m_str6 = m_array_list.GetAt(i).m_str6;
        tmp.m_str7 = m_array_list.GetAt(i).m_str7;
        tmp.m_str8 = m_array_list.GetAt(i).m_str8;
        tmp.m_str9 = m_array_list.GetAt(i).m_str9;
        tmp.m_str10 = m_array_list.GetAt(i).m_str10;
        tmp.m_str11 = m_array_list.GetAt(i).m_str11;
        tmp.m_str12 = m_array_list.GetAt(i).m_str12;

        m_array_list.SetAt(i, m_array_list.GetAt(j));
        m_array_list.SetAt(j, tmp);
}

// entry function of quick sort.
void CSummaryView::QuickSort(int start, int end, int item_num, int order)
{
        if(start >= end)
                return;

        int p = this->QuickSortPartition(start, end, item_num, order);
        this->QuickSort(start, p-1, item_num, order);
        this->QuickSort(p+1, end, item_num, order);

}

// marking message order on header control of summaryview.
void CSummaryView::SetColumnOrderStatus(int status)
{
        int column = status/10;
        int order = status%10;
        LV_COLUMN clm;
        CString buf;

        clm.mask = LVCF_TEXT;
        clm.cchTextMax = BUF_LENGTH;

        // clear all marking
        for(int i=0; i<5; i++){
                clm.pszText = buf.GetBuffer(BUF_LENGTH);
                this->GetListCtrl().GetColumn(i, &clm);
                buf.ReleaseBuffer();
                buf.Replace("▲", ""); buf.Replace("▼", "");
                clm.pszText = buf.GetBuffer(0);
                this->GetListCtrl().SetColumn(i, &clm);
                buf.ReleaseBuffer();
        }

        // set column order on header control.
        clm.pszText = buf.GetBuffer(BUF_LENGTH);
        this->GetListCtrl().GetColumn(column, &clm);
        buf.ReleaseBuffer();

        switch(order){
        case 1:
                buf+="▼";
                break;
        case 2:
                buf+="▲";
                break;
        }

        clm.pszText = buf.GetBuffer(0);
        this->GetListCtrl().SetColumn(column, &clm);

        buf.ReleaseBuffer();
}

void CSummaryView::ReBuildSummary(CString path, int mode)
{
        CFileFind ff;
        BOOL b;
        CHeaderInfo hi;
        CStringArray header;
        SLISTSTACK data;

        m_array_list.RemoveAll();
        m_stack_num = 0;
        m_status_changed = TRUE;

        b = ff.FindFile(path+"\\*.*");
        while(b){
                header.RemoveAll();
                b = ff.FindNextFile();
                if(ff.IsDots())
                        continue;
                if(ff.IsDirectory())
                        continue;
                if(ff.GetFileName().SpanExcluding("0123456789").IsEmpty()){
                        g_file2cstra(path+"\\"+ff.GetFileName(), header); // this is reason why so slow
                        hi.DoIt(header);

                        CString size;
                        size.Format("%d", g_getfs(path + "\\" + ff.GetFileName()));

                        CString subject = hi.GetSubject();
                        subject.Remove('\r');
                        subject.Remove('\n');

                        CString to = hi.GetTo();
                        to.Remove('\r');
                        to.Remove('\n');

                        CString from = hi.GetFrom();
                        from.Remove('\r');
                        from.Remove('\n');

                        CString message_id = hi.GetMsgID();
                        message_id.Remove('\r');
                        message_id.Remove('\n');

                        CString in_reply_to = hi.GetInReplyTo();
                        in_reply_to.Remove('\r');
                        in_reply_to.Remove('\n');

                        CString char_set = hi.GetCharset();
                        char_set.Remove('\r');
                        char_set.Remove('\n');

                        CString date = hi.GetDate();

                        CString stat;
                        // statの設定
                        if(hi.GetBoundary().IsEmpty())
                                stat = "N ";
                        else
                                stat = "NM";

                        data.m_str1 = size;
                        data.m_str2 = subject;
                        // 保存先によってサマリーに表示される情報が違うため
                        if(mode == SMRY_COLUMN_TO)
                                data.m_str3 = to;
                        else
                                data.m_str3 = from;
                        data.m_str4 = date;
                        data.m_str5 = ff.GetFileName();
                        data.m_str6 = stat;
                        data.m_str7 = message_id;
                        data.m_str8 = in_reply_to;
                        data.m_str9 = char_set;
                        m_array_list.Add(data);
                        m_stack_num++;
                }
        }
        this->QuickSort(0, m_array_list.GetSize()-1, NULL, 0);
        this->SetItem(path);
}

void CSummaryView::OnLButtonUp(UINT nFlags, CPoint point) 
{
        // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルトの処理を呼び出してください
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CFolderView *fv = (CFolderView*)mf->m_pTreeV;
        fv->SendMessage(WM_CANCELMODE);
        CListView::OnLButtonUp(nFlags, point);
}

void CSummaryView::OnRclick(NMHDR* pNMHDR, LRESULT* pResult) 
{
        const MSG* msg = GetCurrentMessage();
        CPoint pt1 = msg->pt;
        CPoint pt2 = msg->pt;
        ScreenToClient(&pt1);

        CMenu menu;
        menu.LoadMenu(IDR_SUMMARYVIEW_POPUP);

        CUIntArray ia;
        this->GetSelectedMail(ia);
        if(ia.GetSize() > 1){
                // 削除を無効にする
                menu.EnableMenuItem(ID_SUMMARYVIEW_HEADER_INFO, MF_GRAYED);
                menu.EnableMenuItem(ID_SUMMARYVIEW_RAWMAIL_INFO, MF_GRAYED);
        }else{
                // 有効にする
                menu.EnableMenuItem(ID_SUMMARYVIEW_HEADER_INFO, MF_ENABLED);
                menu.EnableMenuItem(ID_SUMMARYVIEW_RAWMAIL_INFO, MF_ENABLED);
        }

        CMenu *popup = menu.GetSubMenu(0);
        popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON |TPM_LEFTBUTTON, (int)pt2.x, (int)pt2.y, this);
        *pResult = 0;
}

void CSummaryView::OnPopupDel() 
{
        if(this->m_index == -1){
                return;
        }
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CFolderView *fv = (CFolderView *)mf->m_pTreeV;
        CStringArray cstra;
        CUIntArray ia;
        CString message;

        CString current_account = mf->m_pAcntV->GetCurrentAccountName();
        this->GetSelectedMail(ia);
        if(fv->GetSelectedItemKind() != FV_TRASH){
                if(ia.GetSize() == 1){
                        message = this->m_array_list[this->m_stack_num-this->m_index-1].m_str2+"\r\n\r\ntrashに移してもよいですか?";
                }else if(ia.GetSize() > 1){
                        message = "\r\n\r\ntrashに移してもよいですか?";
                }
                if(IDYES != AfxMessageBox(message, MB_YESNO)){
                        return;
                }
                this->MoveMail(ia, app->m_app_path+"\\"+current_account+"\\trash", SMRY_COLUMN_FROM);
        }else{
                if(ia.GetSize() == 1){
                        message = this->m_array_list[this->m_stack_num-this->m_index-1].m_str2+"\r\n\r\n削除してもよいですか?";
                }else if(ia.GetSize() > 1){
                        message = "\r\n\r\n削除してもよいですか?";
                }
                if(IDYES != AfxMessageBox(message, MB_YESNO)){
                        return;
                }               
                this->DeleteMail(ia);
        }
}

void CSummaryView::OnPopupHeaderInfo() 
{
        if(this->m_index == -1){
                return;
        }
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame *)app->m_pMainWnd;
        CTextView *tv = (CTextView *)mf->m_pTextV;
        CString file_name = g_ma(tv->GetCurrentMsgID())+"_header.txt";

        if(!g_is_there(app->m_app_path+"\\temp")) // if attached folder does not exist, create.
                _mkdir(app->m_app_path+"\\temp");
        CString file_path = app->m_app_path+"\\temp\\"+file_name;

        FILE* file = fopen(file_path, "wb");
        fwrite(tv->GetCurrentRawHeader().GetBuffer(0),
                sizeof(char),
                tv->GetCurrentRawHeader().GetLength(),
                file);
        fclose(file);

        CString editor_path = app->GetProfileString("Editor", "Path", "notepad");
        if(editor_path.IsEmpty())
                editor_path = "notepad";
        file_path = "\""+file_path+"\"";
        // open file with editor designated in setting.ini.
        ShellExecute(NULL,NULL, editor_path, file_path, NULL, SW_NORMAL);
}

void CSummaryView::OnPopupRawmailInfo() 
{
        if(this->m_index == -1){
                return;
        }
        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame *)app->m_pMainWnd;
        CTextView *tv = (CTextView *)mf->m_pTextV;
        CString editor_path = app->GetProfileString("Editor", "Path", "notepad");
        if(editor_path.IsEmpty())
                editor_path = "notepad";        
        // open file with editor designated in setting.ini.
        ShellExecute(NULL,NULL, editor_path,
                "\""+tv->GetCurrentPath()+"\"",
                NULL,
                SW_NORMAL);     
}

void CSummaryView::OnPopupRebuild() 
{
        CWaitCursor wait_cursor; // turn cursor into sandglass
        this->ReBuildSummary(this->m_path, SMRY_COLUMN_FROM);
}

void CSummaryView::ClearAllMail(CString path)
{
        CFileFind ff;
        CWaitCursor wait_cursor; // turn cursor into sandglass
        BOOL b = ff.FindFile(path+"\\*.*");
        if(b){
                while(b){
                        b = ff.FindNextFile();
                        if(!ff.IsDirectory() && !ff.IsDots()){
                                DeleteFile(path+"\\"+ff.GetFileName());
                        }
                }
                if(path == this->m_path){
                        // refresh summaryview
                        this->m_array_list.RemoveAll();
                        this->SetItem(path);
                }
        }
}

void CSummaryView::MoveMail(CUIntArray &index_array, CString to, int what_kind_box)
{
        if(to.IsEmpty() || index_array.GetSize() < 1){
                return;
        }
        
        CWaitCursor wait_cursor; // turn cursor into sandglass

        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)app->m_pMainWnd;
        CTextView *tv = (CTextView *)mf->m_pTextV;
        CStringArray cstra;

        int i=0;
        while(i < index_array.GetSize()){
                cstra.RemoveAll();
                g_file2cstra(this->m_path+"\\"+this->m_array_list.GetAt(this->m_stack_num-index_array.GetAt(i)-1).m_str5, cstra);
                this->SaveMail(to, cstra, SMRY_STATUS_NONE, what_kind_box);
                i++;
        }
        this->DeleteMail(index_array);
}

void CSummaryView::Clear()
{
        // first of all, save current summary list into list file
        WriteList();

        CPochyApp *app = (CPochyApp *)AfxGetApp();
        CMainFrame *mf = (CMainFrame*)this->GetParentFrame();
        CListCtrl& lc = GetListCtrl();

        // delete all item;     
        lc.DeleteAllItems();
        this->m_array_list.RemoveAll();
        this->m_stack_num = 0;
        this->m_path.Empty();
        this->m_unread = 0;
        this->m_index = -1;

        // save width of listview column into ini file
        CString num;
        for(int i = 0; i < 5; i++){
                num.Format("%d", i);
                app->WriteProfileInt("SummaryViewColumn", num.GetBuffer(0), lc.GetColumnWidth(i));
        }

        // change column text for default
        this->UpdateColumn(SMRY_COLUMN_FROM);

        // renew infomation of mail in statusbar
        mf->SetStatusBarText(2, "未読 0  メール数 0");
}

void CSummaryView::GetSelectedMail(CUIntArray &index_array)
{
        POSITION pos = this->GetListCtrl().GetFirstSelectedItemPosition();
        index_array.RemoveAll();
        while(pos){
                index_array.Add(this->GetListCtrl().GetNextSelectedItem(pos));
        }
}

/* [<][>][^][v][top][bottom][index][help] */