ファイル化したメールを表示するには?


みけにゃん  URL  2002-10-30 23:24:06  No: 1864

以前の受信したデータをファイル化するには?の続きです。
受信したデータ(POP3)のファイル化まではうまくいったのですが
現在のコードだと受信メニューをクリックすると最初に受信した
ファイルが何個も出来てしまうという事が発生してしまいます。

前回の中でにしのさんが言っていたUIDが一緒のメールをサーバから
落とさなくすることなどを実装したいのですが受信するコードのどこに
どのようなコードを書くと良いのでしょうか?

またリストビューをクリックしたらファイル化したデータを読み込む
ように直したいのですがどう直せばよろしいでしょうか?

リストの読み込みのコードは以下のとおりです。
procedure TMainForm.MailListViewClick(Sender: TObject);
var
  Subject: array [0..HEADER_MAX] of Char;
  Date: array [0..HEADER_MAX] of Char;
  From: array [0..HEADER_MAX] of Char;
  Header: array [0..HEADER_MAX] of Char;
  Body: PChar;
  Size: Integer;
begin
  mSave.Enabled := False;
  mReply.Enabled := False;
  mDelete.Enabled := False;
  mPopupReply.Enabled := False;
  mPopupDelete.Enabled := False;
  ToolButton3.Enabled := False;
  ToolButton5.Enabled := False;

  with MailListView do
  begin
    // 選択されているか?
    if SelCount > 0 then
    begin
    // 見てわかりますが、毎回受信のたびに接続からやってます。
    // 本来であれば ID やパスワードを入力後、一度に受信し、
    // サーバー上から受信したメールを削除し、ファイル等に
    // 保存しておき、題名一覧クリックでは、保存してあるメール
    // を読み込む処理が入るべきでしょう。

    // POP3 サーバーに接続
    S := NMailPop3Connect(PChar(Pop3Name));

    if S <> INVALID_SOCKET then
    begin
      // 選択されている番号が、メールの数より少ないか?
      if Selected.Index < NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag) then
      begin
        // メールのサイズを得て、メモリを確保
        Size := NMailPop3GetMailSize(S, Selected.Index + 1);
        GetMem(Body, Size);
        // メールを読み込む
        NMailPop3GetMail(S, Selected.Index + 1, subject, date, from, header, Body, nil, nil);

        // 表示用の Memo をクリアして受信内容を追加。
        BodyMemo.Lines.Clear;
        BodyMemo.Lines.Add(Strpas(Body));
        // カーソルを先頭に移動
        BodyMemo.SelStart := 0;
        BodyMemo.SelLength := 0;
        // 確保したメモリを開放
        FreeMem(Body);
      end;
    end;

    // 接続終了
    NMailPop3Close(S);

    S := INVALID_SOCKET;
    mSave.Enabled := True;
    mReply.Enabled := True;
    mDelete.Enabled := True;
    mPopupReply.Enabled := True;
    mPopupDelete.Enabled := True;
    ToolButton3.Enabled := True;
    ToolButton5.Enabled := True;
  end;
 end;
end;


にしの  2002-10-31 00:13:15  No: 1865

まずは、詳細設計をされてはどうですか?
このままだと、ずるずる聞いて書くだけになってしまいますよ。
小規模ならば問題ないかもしれませんが、メールソフトとなると、中規模だと思います。
ある程度、設計してからプログラミングしないと、後で行き詰まります。
# 最悪、作り直す羽目になります

UIDLに関しては、前に書いたとおりです。
保存したメールのUIDLは、別途保存する必要があります。
保存したUIDLに、現在読み込もうとするメールのUIDLが存在するか見て、存在すればメールを読み飛ばす、とするだけです。
APIはNMailPop3GetUidlですね。

前に書いたものと同じであれば、選択されたListItemのDataにファイル名があるので、それを読み込みます。
# 前回の中に間違いがありました。ヘッダと本文の間に空行がありませんでした。追加した方が便利です

ヘッダや本文はすでにSJIS化されているので、文字コードの心配はなさそうです。

変換に関しては、
http://www02.so-net.ne.jp/~hat/mailer/rfc.ja.html
このあたりを参考にしてください。


みけにゃん  URL  2002-10-31 01:54:15  No: 1866

詳細仕様はまとまってプログラムをしていて、そこで分からないので
質問していると言うところです。特にファイル化の部分と
そのファイル化したデータの読み込み部分が分からないと言うのが
この質問だったりします。

NMailPop3GetUidlで取得しようとしたのですが
またEAccsessViolationクラスの例外生成がされてしまいました。

コードとしては以下のようなものを考えてみたのですが・・・
try
  NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, StrLen(strUIDL));
  UIDLFs := TFileStream.Create('uidu.lst', fmCreate);
  UDILFs.WriteBuffer(strUDIL^, StrLen(Header)); 
finally
  if UDILFs <> nil then UDILFs.Free;
end;


みけにゃん  URL  2002-10-31 01:58:11  No: 1867

ちょっと変数名をミスしてしまいました。


にしの  2002-10-31 04:01:55  No: 1868

> 詳細仕様はまとまってプログラムをしていて、そこで分からないので
> 質問していると言うところです。特にファイル化の部分と
> そのファイル化したデータの読み込み部分が分からないと言うのが
> この質問だったりします。
それは失礼しました。
前回、今回が繋がっているように見えたので。
早計でした。すみません。

いま環境がないので帰ってから細かいことは書きますが、
strUIDLの型はPCharですよね。Stringでなくarray of charかPCharです。
メモリの確保もしてありますか。

GetMailの手前でGetUidlしてますよね。
# NMailPop3Authenticateした直後、ループの手前です

この時点では、ファイルにせずに、メモリ上に保持し、前回保存してあるUIDLと比較して、前回保存していないUIDLだけとっておきます。
それから(ここからがループ内部)、1つずつGetUidlして、前回保存していないUIDLだったら、メールを取得するようにします。
(ループを抜けた後)全メールを取得し終えたら、今回のUIDLを、前回保存したUIDLに追加します。


にしの  2002-10-31 07:01:56  No: 1869

この場合は、

var
  strUIDL: array [0..HEADER_MAX] of Char;
  UIDLFs: TFileStream;

としておいて、

  UIDLFs := nil;
  try
    NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
    UIDLFs := TFileStream.Create('uidu.lst', fmCreate);
    UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
  finally
    if UIDLFs <> nil then UIDLFs.Free;
  end;

こんな形になります。
strUIDLの長さをHEADER_MAX(8KB)としていますが、メールがたまった状態ではこれ以上になる可能性もあります。
APIには、UIDLの大きさを知る方法はないので、1通ずつのUIDLを取るか、あらかじめ大きく取って、それ以上を仕様とする必要が出てきます。

ファイルにしないのであれば、strUIDLに入れた時点で、TStringListなどに入れて管理すれば楽です。


みけにゃん  URL  2002-10-31 18:12:11  No: 1870

今このコードを入力してみたのですが、生成されたuidu.lstは0バイトで
何も入っていませんでした。strUIDL[0]^ではないのでしょうか?
また過去のと比較する場合は問ういう風に行えばよろしいでしょうか?

実際はVC++/SDKで作っていたメーラなのですが同じ部分で躓いてしまい
新しくDelphiと言う言語を選んでメーラを作ろうと思っていたので
機能仕様などはある程度完成していました。


みけにゃん  URL  2002-10-31 18:29:06  No: 1871

今デバッグしながらファイルを見ていたのですが、UIDLと関係のないような
バイナリのようなNULL文字が出力されるファイルになっていました。
また^でやってみたらコンパイラに止められました。


にしの  2002-10-31 18:33:22  No: 1872

strUIDLを、静的に確保してあれば、
Length(strUIDL)
で問題ないです。
動的に確保したのであれば、Length(strUIDL)を、確保したサイズにしてください。
UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
の部分も、静的に確保した場合です。
動的に確保したのであれば、
UIDLFs.WriteBuffer(strUIDL^, StrLen(strUIDL));
になります。


みけにゃん  URL  2002-10-31 18:34:29  No: 1873

ごめんなさい、上の書込みですがちゃんとリストになって出力されました。(>_<)


みけにゃん  URL  2002-10-31 19:10:50  No: 1874

過去のUIDLのファイルと新しく取得したUIDL(引き込んでメモリ上に展開した方が良い?)を
比べ、該当するメールは受信しないようにするにはどのようにすれば良いでしょうか?


みけにゃん  URL  2002-10-31 22:08:05  No: 1875

10時の書き込みの状態からぜんぜん進めません(>_<)
ちなみに私は仕様設計が出来ていても分かるプログラム以外は
結構苦手だったりするので人に聞いてしまいがちです。(T_T)


みけにゃん  URL  2002-10-31 22:30:28  No: 1876

前の質問に書いてあったものの一部です。

==ここ
・サーバにあるメッセージの全てのUIDLを取得
・現在ローカルに保存してあるメッセージに、サーバ側メッセージのUIDLがあれば、ダウンロードしないようにするチェック
・サーバにあるメッセージで、ローカルにないメッセージを1つずつ読み込む
==ここ

・サーバ側メッセージを削除する設定なら、メッセージを削除
  →これは以下のコードで一応解決しています。

  // サーバにメールを残すのフラグがFalseだったらメールを削除
  if DeleteFlag = False then NMailPop3DeleteMail(S, No);


にしの  2002-11-01 00:40:43  No: 1877

どうやろうとして、どうできなかったんでしょうか。


みけにゃん  URL  2002-11-01 01:36:54  No: 1878

前回までの所でUIDLのリストを保存しましたが、UIDLを比較するには
メモリ上に新しいUIDLを取り込んで過去に取り込んだUIDLのリストと
比べなくてはならないのですが、その部分でどうやって一時的に
メモリに新しいUIDLを引き込んで過去のUIDLのリストと比べて
同じメールは取り込まずに新規メールだけを取り込んで、その上
UIDLのリストを更新すれば良いのかが分からないんです。

一度同じ位置付近にTMemoryStreamを使いメモリ上に新しい
UIDLを展開しようと思ったのですが失敗してしまいました。(>_<)
ちなみに考えてみたリストです。

var
  // 追加変数
  strMUIDL: array [0..HEADER_MAX] of Char;  // メモリ用UIDL引き込み変数
  UIDLMs:   TMemoryStream;                  // メモリストリーム

// メモリ上に新しいUIDLを読み込む
// 現在UIDL.lstを生成している所に記述?
NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strMUIDL, Length(strMUIDL));
UIDLMs := TMemoryStream.Create;
UIDLMs.WriteBuffer(strMUIDL, Length(strMUIDL));

// メモリ上の新しいUIDLと過去のUIDL.lstと比較して古いメールは
// POP3サーバから読み込まない処理が入る(分からないため×)
// ループ内記述?

// メール受信終了後メモリ上のUIDLをUIDL.lstに書き込む
// UIDL.lstはここで生成する?
UIDLFs := nil;

UIDLFs := TFileStream.Create('uidl.lst', fmCreate); // uidl.lstを開く

try
  UIDLFs.WriteBuffer(strMUIDL, Length(strMUIDL));   // リストの更新
finally
  if UIDLFs <> nil then UIDLFs.Free;                // ファイルの解放
end;


にしの  2002-11-01 01:49:53  No: 1879

保存したUIDLは、TStringListで読み込むと楽です。
savedUidl := TStringList.Create;
try
  savedUidl.LoadFromFile('uidl.lst');
except
  ;
end;
これだけで読み込めます。あとは、savedUidl[0]で1行目が読めます。
使い方はヘルプを見てください。

NMailPop3GetUidlしたあとのデータも、同じようにTStringListに入れてしまいます。
nowUidl := TStringList.Create;
nowUidl.Text := strMUIDL;
これだけです。
あとは、savedUidlの各UIDLと、nowUidlの各UIDLを比較して、同じ値があれば、nowUidlの方を消します。
最後に、savedUidlに、nowUidlを追加して保存します。


みけにゃん  URL  2002-11-01 02:32:33  No: 1880

このような感じに記述するのでしょうか?
UIDL.lstの読み込みに失敗(例外が発生)した時は何も入れない方が
良いのでしょうか?

また比較はどの辺りで行えばよろしいのでしょうか?

procedure TMainForm.AddMailList(S: TSocket);
var
  No, Count: integer;
  Subject: array [0..HEADER_MAX] of Char;
  Date: array [0..HEADER_MAX] of Char;
  From: array [0..HEADER_MAX] of Char;
  Header: PChar;
  I: TListItem;
  DataName: String;  // NMLファイルのファイル名
  Seq: Integer;    // シーケンス番号
  Body: PChar;    // Bodyのデータ用
  BodySize: Integer;  // Bodyのファイルサイズ
  Fs: TFileStream;  // ファイルストリーム
  strDate: String;      // 日付の取得
  strUIDL: array [0..HEADER_MAX] of Char;    // UIDLのリスト
  UIDLFs: TFileStream;                       // ファイルストリーム
  strMUIDL: array [0..HEADER_MAX] of Char;   // メモリ用のリスト格納
  UIDLMs: TMemoryStream;                     // メモリストリーム
  SavedUIDL: TStringList;                    // 保存したUIDLの格納
  NowUIDL: TStringList;                      // メモリ側の新しいUIDLの格納
begin
    // メール本文表示をクリア
    BodyMemo.Lines.Clear;
    // ListView もクリア
  HeaderDataClear;
    MailListView.Items.Clear;
    // POP3 サーバに接続する
    S := NMailPop3Connect(PChar(Pop3Name));
    if S <> INVALID_SOCKET then
    begin
        if (Id = '') or (Password = '') then
        begin
           // ID とパスワード入力
           if InputForm.ShowModal = mrOk then
           begin
                Id := InputForm.IdEdit.Text;
                Password := InputForm.PasswordEdit.Text;
           end;
        end;
        // メールの数を得る
        No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

        // 保存したUIDLをTStringListに格納する
        SavedUIDL := TStringList.Create;

        try
          // 保存したUIDL.lstをSavedUIDLに格納
          SavedUIDL.LoadFromFile('uidl.lst');
        except
          // ファイルが読み込めなかった場合はUIDL.lstを作成
          UIDLFs := nil;
          try
            NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
            UIDLFs := TFileStream.Create('uidu.lst', fmCreate);
            UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
          finally
            if UIDLFs <> nil then UIDLFs.Free;
          end;
          SavedUIDL.LoadFromFile('uidl.lst');
        end;

        if No >= 0 then
        begin
            for Count := 1 to No do
            begin
              // 順番にヘッダの内容を読み、ListView に追加
              GetMem(Header, HEADER_MAX);
              NMailPop3GetMailStatus(S, Count, Subject, Date, From, Header, False);
              strDate := StrPas(Date);

              DataName := 'NML' + Copy(strDate, 1, 4)  // yyyy
                  + Copy(strDate, 6, 2)      // mm
                  + Copy(strDate, 9, 2)      // dd
                  + Copy(strDate, 12, 2)    // hh
                  + Copy(strDate, 15, 2)    // mm
                  + Copy(strDate, 18, 2);    // ss

              Seq := 0;

              while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

              try
                BodySize := NMailPop3GetMailSize(S, Count);
                GetMem(Body, BodySize);
                NMailPop3GetMail(S, Count, Subject, Date, From, Header, Body, nil, nil);

                Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);
                Fs.WriteBuffer(Header^, StrLen(Header));
                Fs.WriteBuffer(#13#10, StrLen(#13#10));
                Fs.WriteBuffer(Body^, StrLen(Body));

              finally
                I := MailListView.Items.Add;
                I.Caption := StrPas(Subject);
                I.SubItems.Add(StrPas(Date));
                I.SubItems.Add(StrPas(From));

                if DeleteFlag = False then NMailPop3DeleteMail(S, No);

                if Fs <> nil then Fs.Free;
                if Body <> nil then FreeMem(Body);

              end;
            end;
            TreeView1.Select(TreeView1.Items.Item[1]);
            TreeView1.SetFocus;
        end
        else
        begin
          // サーバーからのエラーメッセージを取得
          NMailGetMessage(NMAIL_GET_ERROR_MESSAGE, Subject, HEADER_MAX);
          MessageDlg('ログインエラー:' + StrPas(Subject), mtError, [mbOK], 0);
        end;
        NMailPop3Close(S);
        S := INVALID_SOCKET;
    end;
end;

全コード載せてしまってごめんなさいです。


にしの  2002-11-01 02:46:12  No: 1881

> UIDL.lstの読み込みに失敗(例外が発生)した時は何も入れない方が
> 良いのでしょうか?

初期状態では、uidl.lstがないはずなので、読み込み時に例外が発生します。
でもこれは失敗とは違いますよね。
だから例外処理をとばす意味で、tryでくくっています。

noには、現在サーバにあるメッセージ数が帰ってきているはずなので、これら一連の操作を、
if No >= 0 then
の後に入れた方がいいかもしれません。
何かしらエラーが発生してログインできなかったときにも、UIDLを取得しに移行としてしまいますから。

あとは、savedUidlとnowUidlが揃ったら、すぐにそれを比較します。
ループの中で、残ったnowUidlを見ながら、メッセージを取得します。
nowUidlには、
'No Uidl'
という形で、格納されていますから、このNoをメッセージ番号として、メッセージを読み込めばいいのです。


みけにゃん  URL  2002-11-01 18:12:21  No: 1882

と言うことはexcept分岐の部分には何も記述しなくて良いのですね?
それとMemoryStreamにもファイル名をつけなくてはならないのでしょうか?
それと比較はこんな感じに行ってOKなのでしょうか?

// ループ内で行う?
if SaveUidl[No] not NowUidl[No] then
begin
  // メールを取り込みnmlファイルに保存する処理
  // 順番にヘッダの内容を読み、ListView に追加
  GetMem(Header, HEADER_MAX);
  NMailPop3GetMailStatus(S, Count, Subject, Date, From, Header, False);
  strDate := StrPas(Date);
  DataName := 'NML' + Copy(strDate, 1, 4) // yyyy
                    + Copy(strDate, 6, 2) // mm
                    + Copy(strDate, 9, 2) // dd
                    + Copy(strDate, 12, 2) // hh
                    + Copy(strDate, 15, 2) // mm
                    + Copy(strDate, 18, 2); // ss

                    Seq := 0;

                    while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

  try
    BodySize := NMailPop3GetMailSize(S, Count);
    GetMem(Body, BodySize);
    NMailPop3GetMail(S, Count, Subject, Date, From, Header, Body, nil, nil);

    Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);
    Fs.WriteBuffer(Header^, StrLen(Header));
    Fs.WriteBuffer(#13#10, StrLen(#13#10));
    Fs.WriteBuffer(Body^, StrLen(Body));

  finally
    I := MailListView.Items.Add;
    I.Caption := StrPas(Subject);
    I.SubItems.Add(StrPas(Date));
    I.SubItems.Add(StrPas(From));

    if DeleteFlag = False then NMailPop3DeleteMail(S, No);

    if Fs <> nil then Fs.Free;
    if Body <> nil then FreeMem(Body);
end
else
begin
   I := MailListView.Items.Add;
   I.Caption := StrPas(Subject);
   I.SubItems.Add(StrPas(Date));
   I.SubItems.Add(StrPas(From));
end;

// UIDLの再保存?


にしの  2002-11-01 18:44:05  No: 1883

> それとMemoryStreamにもファイル名をつけなくてはならないのでしょうか?

MemoryStreamを使う必然性がないと思いますが…。
MemoryStreamのCreateをヘルプで見てください。TFileStreamとは違います。
MemoryStreamでファイル名が必要となるのは、SaveToFileかLoadFromFileくらいでは?

> それと比較はこんな感じに行ってOKなのでしょうか?
だめです。
たとえば、前回3通のメールを取得し、uidl.lstに保存されたUIDL一覧が、
1 thismailis1st
2 thismailis2nd
3 thismailis3rd
だったとします。
それで、2通目(thismailis2nd)を削除し、4通目(thismailis4th)が届いた状態で、またメールを取得しに行くと2通になりますよね。
そのときのUIDL一覧は、
1 thismailis1st
2 thismailis3rd
3 thismailis4th
となります。
上で保存した情報で比較すると、新しく届いたと認識するメールは、thismailis4thだけでなく、thismailis3rdも含まれてしまいます。

一覧を取得したときの記事番号と、UIDLを分離しなければなりません。
分離した上で、UIDLのみ比較します。
# 上の場合は、thismailis1st, thismailis3rdが保存されているから、新規に保存しなければならないのはthismailis4thのみ


にしの  2002-11-01 18:45:08  No: 1884

訂正。
> それで、2通目(thismailis2nd)を削除し、4通目(thismailis4th)が届いた状態で、またメールを取得しに行くと2通になりますよね。
「3通になりますよね」です。
申し訳ない。


みけにゃん  URL  2002-11-01 19:22:48  No: 1885

そうですね。>普通にSavedUIDL[No] = NowUIDL[No]で比べる
メモリストリームの方は理解できました。>ファイル名をつける必要がない

ちなみに今までに作ったメール受信関数部分にコメントをつけてみました。
以下のリストで見てどの部分でメモリストリームに新しいUIDLを引き込み
古いUIDLの比較をどこで行うか教えていただけるとうれしいです。

// POP3からのメール受信
procedure TMainForm.AddMailList(S: TSocket);
var
  No, Count: integer;             // メールの件数用変数
  Subject: array [0..HEADER_MAX] of Char;      // 件名を配列で定義
  Date: array [0..HEADER_MAX] of Char;         // 時刻を配列で定義
  From: array [0..HEADER_MAX] of Char;         // 差出人を配列で定義
  Header: PChar;                               // ヘッダ用変数
  I: TListItem;                                // リスト用変数
  DataName: String;             // NMLファイルのファイル名
  Seq: Integer;               // シーケンス番号
  Body: PChar;               // Bodyのデータ用
  BodySize: Integer;             // Bodyのファイルサイズ
  Fs: TFileStream;             // ファイルストリーム
  strDate: String;             // 日付の取得
  strUIDL: array [0..HEADER_MAX] of Char;      // UIDLのリスト
  UIDLFs: TFileStream;                         // ファイルストリーム
  strMUIDL: array [0..HEADER_MAX] of Char;     // メモリ用のリスト格納
  UIDLMs: TMemoryStream;                       // メモリストリーム
  SavedUIDL: TStringList;                      // 保存したUIDLの格納
  NowUIDL: TStringList;                        // メモリ側の新しいUIDLの格納
begin
  // メール本文表示をクリア
  BodyMemo.Lines.Clear;

  // ListView もクリア
  HeaderDataClear;
  MailListView.Items.Clear;

  // POP3 サーバに接続する
  S := NMailPop3Connect(PChar(Pop3Name));

  // ソケットがエラーでない時はPOP3受信の準備
  if S <> INVALID_SOCKET then
  begin
    // ユーザ名またはパスワードが空白の時は入力ダイアログを表示
    if (Id = '') or (Password = '') then
    begin
      // ユーザ名とパスワード入力
      if InputForm.ShowModal = mrOk then  // 入力ダイアログのOKボタンが押された時
      begin
        // IDとPasswordにユーザ名とパスワードを設定する
        Id := InputForm.IdEdit.Text;
        Password := InputForm.PasswordEdit.Text;
      end;
    end;

    // メールの数を得る(APOP対応なの〜)
    No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

    // 保存したUIDLをTStringListに格納する
    SavedUIDL := TStringList.Create;

    try
      // 保存したUIDL.lstをSavedUIDLに格納
      SavedUIDL.LoadFromFile('uidl.lst');
    except
      ; // 何もしない?
    end;

    // メールの件数が0件以上の場合
    if No >= 0 then
    begin
      for Count := 1 to No do // Countが1からNoまでループ
      begin
        // 順番にヘッダの内容を読み、ListView に追加
        GetMem(Header, HEADER_MAX);
        NMailPop3GetMailStatus(S, Count, Subject, Date, From, Header, False);

        // strDateにDateの内容を渡す(NMLファイルの名前に使用する)
        strDate := StrPas(Date);

        // DataNameにNMLYYYYMMDDHHMMSSを格納する(例NML20021101091022)
        DataName := 'NML' + Copy(strDate, 1, 4)  // yyyy
                  + Copy(strDate, 6, 2)    // mm
                  + Copy(strDate, 9, 2)    // dd
                  + Copy(strDate, 12, 2)  // hh
                  + Copy(strDate, 15, 2)  // mm
                  + Copy(strDate, 18, 2);  // ss

        // Seqに0を代入する
        Seq := 0;

        // 受信フォルダに同名のファイル(例NML20021101091022_0.nml)が
        // 存在する場合はSeq番号を1インクリメントする(例NML20021101091022_1.nml)
        while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

        try
          // 本文の大きさを取得してBodySizeに格納する
          BodySize := NMailPop3GetMailSize(S, Count);
          GetMem(Body, BodySize);  // BodySize分のメモリを確保する

          // POP3からメールを受信する
          NMailPop3GetMail(S, Count, Subject, Date, From, Header, Body, nil, nil);

          // DataName + _ + seq + .nmlファイルを作成する(例NML20021101091022_0.nml)
          Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);
          Fs.WriteBuffer(Header^, StrLen(Header));  // ヘッダをファイルに書き出す
          Fs.WriteBuffer(#13#10, StrLen(#13#10));  // \r\nをファイルに書き出す
          Fs.WriteBuffer(Body^, StrLen(Body));    // 本文をファイルに書き出す

        finally
          I := MailListView.Items.Add;    // リストビューに表示する準備
          I.Caption := StrPas(Subject);         // 件名をリストに表示
          I.SubItems.Add(StrPas(Date));         // 時刻をリストに追加
          I.SubItems.Add(StrPas(From));         // 差出人をリストに追加

          // メールをサーバに残すチェックボタンがチェックされていない時は
          // Noのメールをサーバから削除する
          if DeleteFlag = False then NMailPop3DeleteMail(S, No);

          // FsがNULLの時はFsを解放する
          if Fs <> nil then Fs.Free;

          // BodyがNULLの時はBodyのメモリを解放する
          if Body <> nil then FreeMem(Body);

        end;
      end;   // Countのループの終わり

      // 終了時に新しいUIDLを保存する(一時的に処理をコメント行化)
      {UIDLFs := nil;

      try
        NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate);
        UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;}
    end
    else  // 接続できなかった場合
    begin
      // サーバーからのエラーメッセージを取得
      NMailGetMessage(NMAIL_GET_ERROR_MESSAGE, Subject, HEADER_MAX);
      MessageDlg('POPサーバに接続できませんでした。' + #13#10 + StrPas(Subject), mtError, [mbOK], 0);
    end;
  // POP3サーバから切断する
  NMailPop3Close(S);

  // SocketをINVALID_SOCKETにする
  S := INVALID_SOCKET;
  end;
end;


にしの  2002-11-01 19:48:30  No: 1886

前準備(サーバのメッセージと、保存済みメッセージのUIDLを比較して、保存していないUIDLの一覧を得る)は、

// メールの件数が0件以上の場合
if No >= 0 then
begin

の後ですね。

savedUidl := TStringList.Create;
nowUidl   := TStringList.Create;

NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));

try
  savedUidl.LoadFromFile('uidl.lst');
except
  ;
end;
nowUidl.Text := StrPas(strUIDL);

UidlDelete(nowUidl, savedUidl);

というようにします。
UidlDeleteは、別途用意したもので、次のようなプロシージャです。
# 内部で、noとuidlをばらすUidlSplitプロシージャ(これも準備)を呼び出しています。

// 123 AAAAAを、no=123, Uidl=AAAAAに切り分ける
procedure UidlSplit(Line: string; var no, Uidl: string);
var
  p: integer;
begin
  p := Pos(' ', Line);
  if p = 0 then
  begin
    // 半角スペースがない
    no := '';
    Uidl := Line;
  end
  else
  begin
    no   := Trim(Copy(Line, 1, p));
    Uidl := Trim(Copy(Line, p, Length(Line)));
  end;
end;
procedure UidlDelete(nowUidl, savedUidl: TStringList);
var
  i, j: integer;
  no1, Uidl1: string;
  no2, Uidl2: string;
begin
  for i := nowUidl.Count - 1 downto 0 do
  begin
    UidlSplit(nowUidl[i], no1, Uidl1);
    for j := 0 to savedUidl.Count - 1 do
    begin
      UidlSplit(savedUidl[j], no2, Uidl2);
      if Uidl1 = Uidl2 then
      begin
        nowUidl.Delete(i);
        break;
      end;
    end;
  end;
end;

UidlSplitは、メールを取得するときにも使います。
保存していなくて、かつ、サーバに存在するメッセージのUIDLと、現在読み込もうとしているメッセージのUIDLを比較するためです。
ループに
for Count := 1 to No do
としていますが、これを、

for Count := 1 to nowUidl.Count - 1 do
に変更し、
その中で、
UidlSplit(nowUidl[Count], no, uidl);
と、noとuidlに分解。
そのループ内で、countを渡していたところに、StrToInt(no)を渡します。


みけにゃん  URL  2002-11-01 20:21:42  No: 1887

今上の関数を入れたのですがそのままだと未定義の拡張子
上のprivateの部分に両方の関数の定義をすると別のエラーが
発生したのですがどうすればよいでしょうか?

あと最後に行うUIDLの保存はどうすればよいでしょうか?
よろしくお願いします。


にしの  2002-11-01 20:28:26  No: 1888

エラーの内容がわからなければ答えようがありません。
UIDLの保存は、TStringListのSaveToFileを参照してください。


みけにゃん  URL  2002-11-01 20:47:27  No: 1889

エラーの内容は以下の通りです。(ヒントと警告は除きました)

[エラー] testmain.pas(769): 未定義の識別子 : 'UidlSplit'
[エラー] testmain.pas(93): forward または external 宣言された 'TMainForm.UidlDelete' が見つかりません

ちなみにUidlDeleteもUidlSplitもprivate宣言の所に置きました。
>型の宣言文

UIDLの保存はループを抜けた直後で良いのでしょうか?
>保存の仕方はNowUidl.SaveToFile('uidl.lst');ですね?


みけにゃん  URL  2002-11-01 21:03:00  No: 1890

あともうひとつこのようなエラーも発見しました。

[ヒント] testmain.pas(94): UidlSplit:private 部で宣言されていますが、クラス内でまったく使用されていません


にしの  2002-11-01 21:18:19  No: 1891

未定義の識別子と出るのは、UidlSplitを使用する前に、UidlSplitの定義または実体がないからです。
2つ目のエラーも似たような理由です。
ソースの書き方はわかっていますか?
Cをやっていたのであれば、だいたいわかると思いますが、implementsより前が、C言語で言う関数宣言です。
たとえば、
int main(void)
{
  TStringList *a, *b;
  uidlSplit(a, b);
}
void uidlSplit(TStringList *a, TStringList *b);
だと、mainでuidlSplitを使用した時点では、uidlSplitが定義されていないので警告になりますが、
void uidlSplit(TStringList *a, TStringList *b);
int main(void)
{
  TStringList *a, *b;
  uidlSplit(a, b);
}
ならば、先に定義されているから警告は出ませんね。
同じことを、implementsより前にしているわけです。
今回は、おそらく別のソースからuidlSplit,uidlDeleteを使用することはないと思います。
なので、implementsより前に宣言を用意する必要はありません。
ただし、使う時点より前に実体がないと、使う時点でそのプロシージャが存在するか否かの判断ができません。
つまり、使用しているプロシージャより前に、実体を置かないといけません。

UIDLの保存はいつでもいいですよ。
NowUidlが決定した時点で、savedUidlにnowUidlを加えて保存します。
加えたり保存したりするには、TStringListの関数・プロシージャを参照してください。
簡単です。


みけにゃん  URL  2002-11-01 22:10:50  No: 1892

Cの考え通りに上の方で関数の型を定義して下の方で
その関数の定義を行っています。(C言語もやっているので)
  private
    { Private 宣言 }
    {中略}
    procedure UidlDelete(NowUidl, SavedUidl: TStringList);
    procedure UidlSplit(Line: string; var no, Uidl: string);

関数の実体はend.より上の部分で定義をしています

// UIDLを削除する
procedure UidlDelete(NowUidl, SavedUidl: TStringList);
var
  i, j: integer;
  no1, Uidl1: string;
  no2, Uidl2: string;
begin
  for i := NowUidl.Count - 1 downto 0 do
  begin
    UidlSplit(NowUidl[i], no1, Uidl1);
    for j := 0 to savedUidl.Count - 1 do
    begin
      UidlSplit(SavedUidl[j], no2, Uidl2);
      if Uidl1 = Uidl2 then
      begin
        NowUidl.Delete(i);
        break;
      end;
    end;
  end;
end;
                
// UIDLのリスト表示の1行を切り分ける(例123 AAAAAを、no=123, Uidl=AAAAAに切り分ける)
procedure UidlSplit(Line: string; var no, Uidl: string);
var
  p: integer;
begin
  p := Pos(' ', Line);
  if p = 0 then
  begin
    // 半角スペースがない
    no := '';
    Uidl := Line;
  end
  else
  begin
    no   := Trim(Copy(Line, 1, p));
    Uidl := Trim(Copy(Line, p, Length(Line)));
  end;
end;

end.

やはりこれでは動かないのでしょうか?
その場合はどの辺りまでこの関数を上に移動すればよいでしょうか?
昔こういうのをやっても確かエラーは出ませんでした。

#include <stdio.h>

int plus(int, int);

int main(void){
   int x, y, z;

   x = 1;
   y = 2;
   z = plus(x, y);

   printf("%d+%d=%d\n", x, y, z);

   return(0);
}

int plus(int a, int b){
   return(a + b);
}


にしの  2002-11-01 22:17:11  No: 1893

なるほど。
CはやっていてもC++はやっていませんね。
クラス内関数の実体には、クラス名が必要です。
interface
type
  TClassName=class
  private
    procedure Proc1;
  end;
implements

procedure TClassName.Proc1;
begin

end;

というように。


みけにゃん  URL  2002-11-01 22:30:59  No: 1894

MFCは少々やっていたんですが・・・(>_<)
ほとんど自前の関数を作ることがなかったんでこんな考えに
なってしまうようです。(VBは関数の型の宣言は必要ないでしたっけ?)

なのでまだちょっとどこに置いて良いのか分からない状態です。


にしの  2002-11-01 22:52:11  No: 1895

クラスの宣言の、privateに関数を宣言してあるのなら、同じソース内のどこに置いてもOKですよ。
ただ、実体のほうにはクラス名がなければ駄目なのです。
たとえば、

interface
type
  TClassName1=class
  private
    procedure Proc1;
  end;
  TClassName2=class
  private
    procedure Proc1;
  end;
implements

・・・
とあったとき、
procedure Proc1;
とだけ見てTClassName1とTClassName2のどちらのプロシージャかわかりますか?
それを見分けるために、
procedure TClassName1.Proc1;

procedure TClassName2.Proc1;
というようにクラス名をつけるんです。

ヘルプの、ObjectPascal言語ガイドを参照してください。


にしの  2002-11-01 22:56:01  No: 1896

> クラスの宣言の、privateに関数を宣言してあるのなら、同じソース内のどこに置いてもOKですよ。
語弊がありますね。
実体はimplementation以下に書きます。
Pascal言語の許す範囲で、定義してください。
詳しくはObjectPascal言語ガイドを。


みけにゃん  URL  2002-11-01 23:45:41  No: 1897

上の件は{$R *.DFM}の下に書いて解決しました。
でも今度は以下の事を実行しようと記述をしたらエラーが発生しました。

>UidlSplitは、メールを取得するときにも使います。
>保存していなくて、かつ、サーバに存在するメッセージのUIDLと、現在読み込もう>としているメッセージのUIDLを比較するためです。
>ループに
>for Count := 1 to No do
>としていますが、これを、

>for Count := 1 to nowUidl.Count - 1 doに変更し、
>その中で、UidlSplit(nowUidl[Count], no, uidl);と、noとuidlに分解。
>そのループ内で、countを渡していたところに、StrToInt(no)を渡します。

これを実装したコードは以下の通りです。

// POP3からのメール受信
procedure TMainForm.AddMailList(S: TSocket);
var
  No, Count: integer;             // メールの件数用変数
  Subject: array [0..HEADER_MAX] of Char;      // 件名を配列で定義
  Date: array [0..HEADER_MAX] of Char;         // 時刻を配列で定義
  From: array [0..HEADER_MAX] of Char;         // 差出人を配列で定義
  Header: PChar;                               // ヘッダ用変数
  I: TListItem;                                // リスト用変数
  DataName: String;             // NMLファイルのファイル名
  Seq: Integer;               // シーケンス番号
  Body: PChar;               // Bodyのデータ用
  BodySize: Integer;             // Bodyのファイルサイズ
  Fs: TFileStream;             // ファイルストリーム
  strDate: String;             // 日付の取得
  strUIDL: array [0..HEADER_MAX] of Char;      // UIDLのリスト
  UIDLFs: TFileStream;                         // ファイルストリーム
  strMUIDL: array [0..HEADER_MAX] of Char;     // メモリ用のリスト格納
  UIDLMs: TMemoryStream;                       // メモリストリーム
  SavedUIDL: TStringList;                      // 保存したUIDLの格納
  NowUIDL: TStringList;                        // メモリ側の新しいUIDLの格納
  sUIDL: String;                                // 分解したUIDLの格納
begin
  // メール本文表示をクリア
  BodyMemo.Lines.Clear;

  // ListView もクリア
  HeaderDataClear;
  MailListView.Items.Clear;

  // POP3 サーバに接続する
  S := NMailPop3Connect(PChar(Pop3Name));

  // ソケットがエラーでない時はPOP3受信の準備
  if S <> INVALID_SOCKET then
  begin
    // ユーザ名またはパスワードが空白の時は入力ダイアログを表示
    if (Id = '') or (Password = '') then
    begin
      // ユーザ名とパスワード入力
      if InputForm.ShowModal = mrOk then  // 入力ダイアログのOKボタンが押された時
      begin
        // IDとPasswordにユーザ名とパスワードを設定する
        Id := InputForm.IdEdit.Text;
        Password := InputForm.PasswordEdit.Text;
      end;
    end;

    // メールの数を得る(APOP対応なの〜)
    No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

    // 保存したUIDLをTStringListに格納する
    SavedUIDL := TStringList.Create;
    NowUIDL   := TStringList.Create;

    try
      // 保存したUIDL.lstをSavedUIDLに格納
      SavedUIDL.LoadFromFile('uidl.lst');
    except
      ; // 何もしない?
    end;

    // 新しいUIDLのテキストにstrUIDLの内容を代入する
    NowUidl.Text := StrPas(strUIDL);

    // 新しいUIDLと比較して古いUIDLの情報を削除する
    UidlDelete(nowUidl, savedUidl);

    // メールの件数が0件以上の場合
    if No >= 0 then
    begin
      for Count := 1 to NowUidl.Count - 1 do // Countが1からnowUidl.Count - 1までループ
      begin
        // UIDLのリストを切り分ける
        UidlSplit(NowUidl[Count], No, sUIDL);

        // 順番にヘッダの内容を読み、ListView に追加
        GetMem(Header, HEADER_MAX);
        NMailPop3GetMailStatus(S, StrToInt(No), Subject, Date, From, Header, False);

        // strDateにDateの内容を渡す(NMLファイルの名前に使用する)
        strDate := StrPas(Date);

        // DataNameにNMLYYYYMMDDHHMMSSを格納する(例NML20021101091022)
        DataName := 'NML' + Copy(strDate, 1, 4)  // yyyy
                  + Copy(strDate, 6, 2)    // mm
                  + Copy(strDate, 9, 2)    // dd
                  + Copy(strDate, 12, 2)  // hh
                  + Copy(strDate, 15, 2)  // mm
                  + Copy(strDate, 18, 2);  // ss

        // Seqに0を代入する
        Seq := 0;

        // 受信フォルダに同名のファイル(例NML20021101091022_0.nml)が
        // 存在する場合はSeq番号を1インクリメントする(例NML20021101091022_1.nml)
        while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

        try
          // 本文の大きさを取得してBodySizeに格納する
          BodySize := NMailPop3GetMailSize(S, StrToInt(No));
          GetMem(Body, BodySize);  // BodySize分のメモリを確保する

          // POP3からメールを受信する
          NMailPop3GetMail(S, StrToInt(No), Subject, Date, From, Header, Body, nil, nil);

          // DataName + _ + seq + .nmlファイルを作成する(例NML20021101091022_0.nml)
          Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);
          Fs.WriteBuffer(Header^, StrLen(Header));  // ヘッダをファイルに書き出す
          Fs.WriteBuffer(#13#10, StrLen(#13#10));  // \r\nをファイルに書き出す
          Fs.WriteBuffer(Body^, StrLen(Body));    // 本文をファイルに書き出す

        finally
          I := MailListView.Items.Add;      // リストビューに表示する準備
          I.Caption := StrPas(Subject);           // 件名をリストに表示
          I.SubItems.Add(StrPas(Date));           // 時刻をリストに追加
          I.SubItems.Add(StrPas(From));           // 差出人をリストに追加

          // メールをサーバに残すチェックボタンがチェックされていない時は
          // Noのメールをサーバから削除する
          if DeleteFlag = False then NMailPop3DeleteMail(S, No);

          // FsがNULLの時はFsを解放する
          if Fs <> nil then Fs.Free;

          // BodyがNULLの時はBodyのメモリを解放する
          if Body <> nil then FreeMem(Body);

        end;
      end;   // Countのループの終わり

      // 終了時に新しいUIDLを保存する(一時的に処理をコメント行化)
      {UIDLFs := nil;

      try
        NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate);
        UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;}
    end
    else  // 接続できなかった場合
    begin
      // サーバーからのエラーメッセージを取得
      NMailGetMessage(NMAIL_GET_ERROR_MESSAGE, Subject, HEADER_MAX);
      MessageDlg('POPサーバに接続できませんでした。' + #13#10 + StrPas(Subject), mtError, [mbOK], 0);
    end;
  // POP3サーバから切断する
  NMailPop3Close(S);

  // SocketをINVALID_SOCKETにする
  S := INVALID_SOCKET;
  end;
end;

そしてエラー内容は以下の通りです。
[エラー] testmain.pas(406): 変数実パラメータと変数仮パラメータとは同一の型でなければなりません
[エラー] testmain.pas(410): 'String' と 'Integer' には互換性がありません
[エラー] testmain.pas(432): 'String' と 'Integer' には互換性がありません
[エラー] testmain.pas(436): 'String' と 'Integer' には互換性がありません
[致命的エラー] nmail.dpr(11): 'testmain.pas' ユニットはコンパイルできませんでした


にしの  2002-11-02 01:29:02  No: 1898

それは聞くよりソースを見直した方がいいですよ。
そのエラーの原因がわからないと言うことは、Delphiのソースがわからないということになります。
ケアレスミスです。


みけにゃん  URL  2002-11-02 01:48:00  No: 1899

今の所はエラーになった部分をコメント化または前のコードに直しています。
以下にエラーの部分を書いておきます。

[エラー] testmain.pas(406): 変数実パラメータと変数仮パラメータとは同一の型でなければなりません
// UIDLのリストを切り分ける
UidlSplit(NowUidl[Count], No, sUIDL);

NMailPop3GetMailStatus(S, StrToInt(No), Subject, Date, From, Header, False);

while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

// 本文の大きさを取得してBodySizeに格納する
BodySize := NMailPop3GetMailSize(S, StrToInt(No));

// POP3からメールを受信する
NMailPop3GetMail(S, StrToInt(No), Subject, Date, From, Header, Body, nil, nil);

Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);


みけにゃん  URL  2002-11-02 01:52:27  No: 1900

下のところに書くのを忘れてしまいました。>エラー内容

[エラー] testmain.pas(410): 'String' と 'Integer' には互換性がありません
[エラー] testmain.pas(432): 'String' と 'Integer' には互換性がありません
[エラー] testmain.pas(436): 'String' と 'Integer' には互換性がありません

NMailPop3GetMailStatus(S, StrToInt(No), Subject, Date, From, Header, False);

while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

// 本文の大きさを取得してBodySizeに格納する
BodySize := NMailPop3GetMailSize(S, StrToInt(No));

// POP3からメールを受信する
NMailPop3GetMail(S, StrToInt(No), Subject, Date, From, Header, Body, nil, nil);

Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);


みけにゃん  URL  2002-11-02 02:23:25  No: 1901

ちょっと埒があかなくなってきたので一度少し前の状態に戻してみました。(>_<)

また一度uidl.lstを消して受信を試みましたがuidl.lstを開けない
例外で止まってしまいました。

// POP3からのメール受信
procedure TMainForm.AddMailList(S: TSocket);
var
  No, Count: integer;             // メールの件数用変数
  Subject: array [0..HEADER_MAX] of Char;      // 件名を配列で定義
  Date: array [0..HEADER_MAX] of Char;         // 時刻を配列で定義
  From: array [0..HEADER_MAX] of Char;         // 差出人を配列で定義
  Header: PChar;                               // ヘッダ用変数
  I: TListItem;                                // リスト用変数
  DataName: String;             // NMLファイルのファイル名
  Seq: Integer;               // シーケンス番号
  Body: PChar;               // Bodyのデータ用
  BodySize: Integer;             // Bodyのファイルサイズ
  Fs: TFileStream;             // ファイルストリーム
  strDate: String;             // 日付の取得
  strUIDL: array [0..HEADER_MAX] of Char;      // UIDLのリスト
  UIDLFs: TFileStream;                         // ファイルストリーム
  strMUIDL: array [0..HEADER_MAX] of Char;     // メモリ用のリスト格納
  UIDLMs: TMemoryStream;                       // メモリストリーム
  SavedUIDL: TStringList;                      // 保存したUIDLの格納
  NowUIDL: TStringList;                        // メモリ側の新しいUIDLの格納
  sUIDL: String;                                // 分解したUIDLの格納
begin
  // メール本文表示をクリア
  BodyMemo.Lines.Clear;

  // ListView もクリア
  HeaderDataClear;
  MailListView.Items.Clear;

  // POP3 サーバに接続する
  S := NMailPop3Connect(PChar(Pop3Name));

  // ソケットがエラーでない時はPOP3受信の準備
  if S <> INVALID_SOCKET then
  begin
    // ユーザ名またはパスワードが空白の時は入力ダイアログを表示
    if (Id = '') or (Password = '') then
    begin
      // ユーザ名とパスワード入力
      if InputForm.ShowModal = mrOk then  // 入力ダイアログのOKボタンが押された時
      begin
        // IDとPasswordにユーザ名とパスワードを設定する
        Id := InputForm.IdEdit.Text;
        Password := InputForm.PasswordEdit.Text;
      end;
    end;

    // メールの数を得る(APOP対応なの〜)
    No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

    // 保存したUIDLをTStringListに格納する
    SavedUIDL := TStringList.Create;
    NowUIDL   := TStringList.Create;

    try
      // 保存したUIDL.lstをSavedUIDLに格納
      SavedUIDL.LoadFromFile('uidl.lst');
    except
      ; // 何もしない?
    end;

    // 新しいUIDLのテキストにstrUIDLの内容を代入する
    NowUidl.Text := StrPas(strUIDL);

    // 新しいUIDLと比較して古いUIDLの情報を削除する
    UidlDelete(NowUidl, SavedUidl);

    // メールの件数が0件以上の場合
    if No >= 0 then
    begin
      for Count := 1 to No do // Countが1からnowUidl.Count - 1までループ
      begin
        // UIDLのリストを切り分ける
        {UidlSplit(NowUidl[Count], No, sUIDL);}

        // 順番にヘッダの内容を読み、ListView に追加
        GetMem(Header, HEADER_MAX);
        NMailPop3GetMailStatus(S, Count, Subject, Date, From, Header, False);

        // strDateにDateの内容を渡す(NMLファイルの名前に使用する)
        strDate := StrPas(Date);

        // DataNameにNMLYYYYMMDDHHMMSSを格納する(例NML20021101091022)
        DataName := 'NML' + Copy(strDate, 1, 4)  // yyyy
                  + Copy(strDate, 6, 2)    // mm
                  + Copy(strDate, 9, 2)    // dd
                  + Copy(strDate, 12, 2)  // hh
                  + Copy(strDate, 15, 2)  // mm
                  + Copy(strDate, 18, 2);  // ss

        // Seqに0を代入する
        Seq := 0;

        // 受信フォルダに同名のファイル(例NML20021101091022_0.nml)が
        // 存在する場合はSeq番号を1インクリメントする(例NML20021101091022_1.nml)
        while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

        try
          // 本文の大きさを取得してBodySizeに格納する
          BodySize := NMailPop3GetMailSize(S, Count);
          GetMem(Body, BodySize);  // BodySize分のメモリを確保する

          // POP3からメールを受信する
          NMailPop3GetMail(S, Count, Subject, Date, From, Header, Body, nil, nil);

          // DataName + _ + seq + .nmlファイルを作成する(例NML20021101091022_0.nml)
          Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);
          Fs.WriteBuffer(Header^, StrLen(Header));  // ヘッダをファイルに書き出す
          Fs.WriteBuffer(#13#10, StrLen(#13#10));  // \r\nをファイルに書き出す
          Fs.WriteBuffer(Body^, StrLen(Body));    // 本文をファイルに書き出す

        finally
          I := MailListView.Items.Add;      // リストビューに表示する準備
          I.Caption := StrPas(Subject);           // 件名をリストに表示
          I.SubItems.Add(StrPas(Date));           // 時刻をリストに追加
          I.SubItems.Add(StrPas(From));           // 差出人をリストに追加

          // メールをサーバに残すチェックボタンがチェックされていない時は
          // Noのメールをサーバから削除する
          if DeleteFlag = False then NMailPop3DeleteMail(S, No);

          // FsがNULLの時はFsを解放する
          if Fs <> nil then Fs.Free;

          // BodyがNULLの時はBodyのメモリを解放する
          if Body <> nil then FreeMem(Body);

        end;
      end;   // Countのループの終わり

      // 終了時に新しいUIDLを保存する(一時的に処理をコメント行化)
      {UIDLFs := nil;

      try
        NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate);
        UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;}
    end
    else  // 接続できなかった場合
    begin
      // サーバーからのエラーメッセージを取得
      NMailGetMessage(NMAIL_GET_ERROR_MESSAGE, Subject, HEADER_MAX);
      MessageDlg('POPサーバに接続できませんでした。' + #13#10 + StrPas(Subject), mtError, [mbOK], 0);
    end;
  // POP3サーバから切断する
  NMailPop3Close(S);

  // SocketをINVALID_SOCKETにする
  S := INVALID_SOCKET;
  end;
end;


みけにゃん  URL  2002-11-03 07:15:28  No: 1902

何度か原因を考えてみたのですが、やっぱり分からない状態です。
>前回のミスについて(コードを印刷してみましたが分かりませんでした。)

現在開発環境がない場所にいるので何も出来ないのですが
休み明けからまた続きをしようと思っているのでよろしくお願いします。
プログラマ志望なのにこんなのじゃだめですね・・・(>_<)


にしの  2002-11-03 18:51:07  No: 1903

変数の型について、理解していますか?
たとえば、
var
  Num: Integer;
begin
  Num := '12345';
これがエラーになる原因はわかりますか?

エラーの原因は、たいていエラーが起きている部分と、エラーが起きている部分で使っている変数が定義されているところ、関数が定義されているところの3つがわかればわかります。
# ソースを全掲するのはよくないです。

今回の場合は、
[変数の定義]
No, Count: integer;       // メールの件数用変数
NowUIDL: TStringList;
sUIDL: String;
[関数の定義]
procedure UidlSplit(Line: string; var no, Uidl: string);
[エラー箇所]
UidlSplit(NowUidl[Count], No, sUIDL);

がわかれば、エラーの原因・対処法がわかります。

C言語を知っているようですので、C言語の例を出してみます。
#include<stdio.h>
#include<stdlib.h>

void UidlSplit(char *line, char *no, char *uidl)
{
 /* 省略 */
}

int main(void)
{
  char[] localLine = "1 uidl0001";
  char   localUidl[128];
  int    localNo;

  UidlSplit(localLine, localNo, localUidl);

  return 0;
}
これがエラーになる原因はわかりますか?
同じ理由です。
これがわからないのであれば、Delphiの型について勉強し直した方がいいです。
# 初歩的な間違いですから

ちなみに、プログラマ志望ということですが、ある程度できれば問題ないと思いますよ。
学生(または日曜プログラマ)として勉強していた内容が、仕事ではあまり使えませんから。
基本だけは変わりませんが、仕事の場合はそれに加えて納期と工数が最重要項目になります。
# 会社によって方針は違うでしょうけどね
納期を守るためには、今まで美しいソースを目指して書いていた物が、気がついたら他の人に読めないソースになっていたり、工数が足りなくなって中途半端(といっても動作する)なまま納品したり…。


みけにゃん  URL  2002-11-05 18:04:03  No: 1904

>int main(void)
>{
>  char[] localLine = "1 uidl0001";
>  char   localUidl[128];
>  int    localNo;
>
>  UidlSplit(localLine, localNo, localUidl);
>
>  return 0;
>}

もちろんこのエラーについては分かります。

型についてはVBも高校ぐらいからやっていたので型変換で
直るようなのですが、以下のコードでは何も変換について
述べていなかったのでそのまま記述したらStringとIntegerには
互換性がないというエラーが出てしまいました。

>UidlSplitは、メールを取得するときにも使います。
>保存していなくて、かつ、サーバに存在するメッセージのUIDLと、現在読み込もう>としているメッセージのUIDLを比較するためです。
>ループに
>for Count := 1 to No do
>としていますが、これを、

>for Count := 1 to nowUidl.Count - 1 doに変更し、
>その中で、UidlSplit(nowUidl[Count], no, uidl);と、noとuidlに分解。
>そのループ内で、countを渡していたところに、StrToInt(no)を渡します。

でもStrToIntでString(文字列型)をInterger(整数)型に変換しているのに
どうして互換性のないというエラーが出たのかがいまいち分かりません。


みけにゃん  URL  2002-11-05 19:03:23  No: 1905

SplitUIDLの引数を見たらすぐに分かったのですが
noは文字列定義されているのにこのプロシージャ内で
使われているNoは整数型で取られているからエラーが起こるんですね。

でもこの場合どうすればこの状況を回避できるか分からないです。(>_<)
Noは1つしか定義できないですから。(C++だとオーバーロードが使えるのですが・・・)


にしの  2002-11-05 19:32:10  No: 1906

単純に、Noを文字列型に定義すればいいのでは?
オーバーロードは、Delphiにももちろん存在します。
ヘルプ「ObjectPascal言語ガイド」の、「メソッドのオーバーロード」を参照してください。


みけにゃn  URL  2002-11-05 19:50:53  No: 1907

>「ObjectPascal言語ガイド」の、「メソッドのオーバーロード」を参照
変数のオーバーロードではなくて関数のオーバロードみたいです。

でもメソッドではなくて変数の二重定義(この場合StringとInteger)って
出来るのでしょうか?

出来なければStringの方はmNoとして別定義しようと思います。
これが終わったら次は保存するかしないかの分岐なのですが・・・。


みけにゃん  URL  2002-11-05 20:02:10  No: 1908

変数の二重定義はエラーになるのでmNoと言うString型の定義を作り
Countを入れていたところにStrToInt(mNo)を入れてみたら問題なく
動作しました。でも新たなエラーとしてNowUIDLのStringListの
内容がないため例外エラーが発生して受信できないで止まってしまいました。
最初の方でNowUIDLに現在の新しいUIDLをNMailPop3GetUidlで取得して
NowUIDLに渡すにはどうすればよいでしょうか?


みけにゃん  URL  2002-11-05 20:16:51  No: 1909

また問題点コードリストを載せます。(毎回長文でごめんなさい)

今このコードで動かすとメールをぜんぜん受信しません。
あと必ずUIDL.lstを削除すると読み込み例外が出るので
空のファイルを作って読み込ませた方が良さそうなのですが
やり方はどうすれば良いでしょうか?

TFileStream.WriteBuffer('', 0);を使って空のファイルは
作れるのでしょうか?

// POP3からのメール受信
procedure TMainForm.AddMailList(S: TSocket);
var
  No, Count: integer;             // メールの件数用変数
  mNo: String;                                  // SplitUidl用の変数
  Subject: array [0..HEADER_MAX] of Char;      // 件名を配列で定義
  Date: array [0..HEADER_MAX] of Char;         // 時刻を配列で定義
  From: array [0..HEADER_MAX] of Char;         // 差出人を配列で定義
  Header: PChar;                               // ヘッダ用変数
  I: TListItem;                                // リスト用変数
  DataName: String;             // NMLファイルのファイル名
  Seq: Integer;               // シーケンス番号
  Body: PChar;               // Bodyのデータ用
  BodySize: Integer;             // Bodyのファイルサイズ
  Fs: TFileStream;             // ファイルストリーム
  strDate: String;             // 日付の取得
  strUIDL: array [0..HEADER_MAX] of Char;      // UIDLのリスト
  UIDLFs: TFileStream;                         // ファイルストリーム
  SavedUIDL: TStringList;                      // 保存したUIDLの格納
  NowUIDL: TStringList;                        // メモリ側の新しいUIDLの格納
  sUIDL: String;                                // 分解したUIDLの格納
  nUIDL: TMemoryStream;                         // メモリストリーム
  nUIDLs: array [0..HEADER_MAX] of Char;      // 新しいUIDLのリスト
begin
  // メール本文表示をクリア
  BodyMemo.Lines.Clear;

  // ListView もクリア
  HeaderDataClear;
  MailListView.Items.Clear;

  // POP3 サーバに接続する
  S := NMailPop3Connect(PChar(Pop3Name));

  // ソケットがエラーでない時はPOP3受信の準備
  if S <> INVALID_SOCKET then
  begin
    // ユーザ名またはパスワードが空白の時は入力ダイアログを表示
    if (Id = '') or (Password = '') then
    begin
      // ユーザ名とパスワード入力
      if InputForm.ShowModal = mrOk then  // 入力ダイアログのOKボタンが押された時
      begin
        // IDとPasswordにユーザ名とパスワードを設定する
        Id := InputForm.IdEdit.Text;
        Password := InputForm.PasswordEdit.Text;
      end;
    end;

    // メールの数を得る(APOP対応)
    No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

    nUIDL := TMemoryStream.Create;
    NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, nUIDLs, Length(nUIDLs));
    nUIDL.WriteBuffer(nUIDLs, StrLen(nUIDLs));

    // 保存したUIDLをTStringListに格納する
    SavedUIDL := TStringList.Create;
    NowUIDL   := TStringList.Create;

    try
      // 保存したUIDL.lstをSavedUIDLに格納
      SavedUIDL.LoadFromFile('uidl.lst');
    except
      ; // 何もしない?(例外発生)
    end;

    // 新しいUIDLのテキストにstrUIDLの内容を代入する
    NowUidl.Text := StrPas(strUIDL);

    // 新しいUIDLと比較して古いUIDLの情報を削除する
    UidlDelete(NowUidl, SavedUidl);

    // メールの件数が0件以上の場合
    if No >= 0 then
    begin
      for Count := 1 to nowUidl.Count{No} - 1 do // Countが1からnowUidl.Count - 1までループ
      begin
        // UIDLのリストを切り分ける
        UidlSplit(NowUidl[Count], mNo, sUIDL);

        // 順番にヘッダの内容を読み、ListView に追加
        GetMem(Header, HEADER_MAX);
        NMailPop3GetMailStatus(S, StrToInt(mNo){Count}, Subject, Date, From, Header, False);

        // strDateにDateの内容を渡す(NMLファイルの名前に使用する)
        strDate := StrPas(Date);

        // DataNameにNMLYYYYMMDDHHMMSSを格納する(例NML20021101091022)
        DataName := 'NML' + Copy(strDate, 1, 4)  // yyyy
                  + Copy(strDate, 6, 2)    // mm
                  + Copy(strDate, 9, 2)    // dd
                  + Copy(strDate, 12, 2)  // hh
                  + Copy(strDate, 15, 2)  // mm
                  + Copy(strDate, 18, 2);  // ss

        // Seqに0を代入する
        Seq := 0;

        // 受信フォルダに同名のファイル(例NML20021101091022_0.nml)が
        // 存在する場合はSeq番号を1インクリメントする(例NML20021101091022_1.nml)
        while FileExists(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml') do Inc(Seq);

        try
          // 本文の大きさを取得してBodySizeに格納する
          BodySize := NMailPop3GetMailSize(S, StrToInt(mNo){Count});
          GetMem(Body, BodySize);  // BodySize分のメモリを確保する

          // POP3からメールを受信する
          NMailPop3GetMail(S, StrToInt(mNo){Count}, Subject, Date, From, Header, Body, nil, nil);

          // DataName + _ + seq + .nmlファイルを作成する(例NML20021101091022_0.nml)
          Fs := TFileStream.Create(RcvFolder + 'RcvMail\' + DataName + '_' + IntToStr(Seq) + '.nml', fmCreate);
          Fs.WriteBuffer(Header^, StrLen(Header));  // ヘッダをファイルに書き出す
          Fs.WriteBuffer(#13#10, StrLen(#13#10));  // \r\nをファイルに書き出す
          Fs.WriteBuffer(Body^, StrLen(Body));    // 本文をファイルに書き出す

        finally
          I := MailListView.Items.Add;      // リストビューに表示する準備
          I.Caption := StrPas(Subject);           // 件名をリストに表示
          I.SubItems.Add(StrPas(Date));           // 時刻をリストに追加
          I.SubItems.Add(StrPas(From));           // 差出人をリストに追加

          // メールをサーバに残すチェックボタンがチェックされていない時は
          // Noのメールをサーバから削除する
          if DeleteFlag = False then NMailPop3DeleteMail(S, No);

          // FsがNULLの時はFsを解放する
          if Fs <> nil then Fs.Free;

          // BodyがNULLの時はBodyのメモリを解放する
          if Body <> nil then FreeMem(Body);

        end;
      end;   // Countのループの終わり

      // 終了時に新しいUIDLを保存する(一時的に処理をコメント行化)
      UIDLFs := nil;

      try
        NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate);
        UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;
    end
    else  // 接続できなかった場合
    begin
      // サーバーからのエラーメッセージを取得
      NMailGetMessage(NMAIL_GET_ERROR_MESSAGE, Subject, HEADER_MAX);
      MessageDlg('POPサーバに接続できませんでした。' + #13#10 + StrPas(Subject), mtError, [mbOK], 0);
    end;
  // POP3サーバから切断する
  NMailPop3Close(S);

  // SocketをINVALID_SOCKETにする
  S := INVALID_SOCKET;
  end;
end;


にしの  2002-11-05 20:46:24  No: 1910

> 変数のオーバーロードではなくて関数のオーバロードみたいです。
C言語でも変数をオーバーロードすることはできませんよ。
何がやりたいのでしょうか。

長文を載せる前に、なぜ問題点のみに絞って載せないのですか?
以前提示した関数を使えば、この問題は解決できます。
まずは、なぜ解決できないのかを自力で調べてみてはどうですか?
提示されたものでできないから、新しい方法でやってみたがそれも駄目、となると、わからないことの山積みで終わってしまいますよ。


みけにゃん  URL  2002-11-05 21:39:26  No: 1911

そうですね、結構わがままなところがあるので大きく載せて
答えて下さいと言ってしまう所があるので気をつけます。>にしのさん

一つずつ解決すると言うことでまずは新しいUIDLを取り込む所が
どうやって橋渡しすればよいか分からないのですがどうやれば
良いのでしょう?またuidl.lstがない時にexceptに行かずに
エラーで止まってしまうのですがこれはどうしてでしょうか?
・・・これでは2つの質問になってしまいました。ごめんなさいです。

  // メールの数を得る(APOP対応)
    No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

    // NowUIDLのリストに現在のUIDLを引き込む?
    nUIDL := TMemoryStream.Create;
    NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, nUIDLs, Length(nUIDLs));
    nUIDL.WriteBuffer(nUIDLs, StrLen(nUIDLs));

    // 保存したUIDLをTStringListに格納する
    SavedUIDL := TStringList.Create;
    NowUIDL   := TStringList.Create;

    try
      // 保存したUIDL.lstをSavedUIDLに格納
      SavedUIDL.LoadFromFile('uidl.lst');
    except
      try
        // 初回起動(またはuidl.lstファイルがない)時に空のファイルを作って読み込む
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate); // 何もしない?(例外発生)
        UIDLFs.WriteBuffer('', StrLen(''));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;
      SavedUIDL.LoadFromFile('uidl.lst');
    end;

    // 新しいUIDLのテキストにstrUIDLの内容を代入する
    NowUidl.Text := StrPas(strUIDL);


にしの  2002-11-05 21:53:11  No: 1912

> 一つずつ解決すると言うことでまずは新しいUIDLを取り込む所が
> どうやって橋渡しすればよいか分からないのですがどうやれば
> 良いのでしょう?

これは、
 // 新しいUIDLのテキストにstrUIDLの内容を代入する
    NowUidl.Text := StrPas(strUIDL);
ですよ。
TStringListクラスの、Textプロパティを見てください。
ここに文字列を入れると、Stringsプロパティに各行ごと切り分けられます。
つまり、
StringList.Text := 'abc'#13#10'def'#13#10'ghi';
は、
StringList.Clear; // 内容を破棄
StringList.Add('abc'); //一行('abc')追加
StringList.Add('def'); //一行('def')追加
StringList.Add('ghi'); //一行('ghi')追加
と同じです。

> またuidl.lstがない時にexceptに行かずに
> エラーで止まってしまうのですがこれはどうしてでしょうか?

デバッグオプションの初期値では、例外が発生すると止まります。
実際のEXEを直接起動すれば出ないはずです。
デバッグするわけだから、例外の発生がわからないと困ることがありますよね。そのためです。
いらないのであれば、デバッグオプションを変更してください。
# この辺は僕も詳しくないです。ヘルプを見た方が早いかも


にしの  2002-11-05 21:55:49  No: 1913

SavedUIDL.LoadFromFile('uidl.lst');
も例外を発生するので、tryでくくる必要があります。
ただし、ファイルがなくても空なのは変わりないので、

SavedUIDL.Clear;
try
  SavedUIDL.LoadFromFile('uidl.lst');
except
  ;
end;
でOKです。


みけにゃん  URL  2002-11-05 22:11:28  No: 1914

と言うことは1つ目の答えは以下の通りで良いのですか?

    // メールの数を得る(APOP対応)
    No := NMailPop3Authenticate(S, PChar(Id), PChar(Password), ApopFlag);

    // 新しいUIDLを取得する
    NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));

    // 新しいUIDLと保存したUIDLを格納するTStringListを作る
    SavedUIDL := TStringList.Create;
    NowUIDL   := TStringList.Create;

    try
      // 保存したUIDL.lstをSavedUIDLに格納
      SavedUIDL.LoadFromFile('uidl.lst');
    except
      try
        // 初回起動(またはuidl.lstファイルがない)時に空のファイルを作って読み込む
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate); // 何もしない?(例外発生)
        UIDLFs.WriteBuffer('', StrLen(''));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;
      SavedUIDL.LoadFromFile('uidl.lst');
    end;

    // 新しいUIDLのStringListのテキストにstrUIDL(新しいUIDL)の内容を代入する
    NowUidl.Text := StrPas(strUIDL);

2つ目はEXEから実行すれば問題なくファイルは出来るようです。
次の質問は分かり次第書きます。


みけにゃん  URL  2002-11-05 22:29:12  No: 1915

えっと次の質問なのですが、最後の新しいUIDLの保存部分なのですが
以下のようなもので良いのでしょうか?(ちなみにループ後の処理です)

      // 終了時に新しいUIDLを保存する(一時的に処理をコメント行化)
      UIDLFs := nil;

      try
        NMailPop3GetUidl(S, NMAIL_GET_UIDL_ALL, strUIDL, Length(strUIDL));
        UIDLFs := TFileStream.Create('uidl.lst', fmCreate);
        UIDLFs.WriteBuffer(strUIDL[0], StrLen(strUIDL));
      finally
        if UIDLFs <> nil then UIDLFs.Free;
      end;


にしの  2002-11-05 23:35:05  No: 1916

ファイルがなければ作成、の部分は少し冗長ですね。
ない場合は読み込んでも空ですから、再度読み込む必要はありません。

try
  // 保存したUIDL.lstをSavedUIDLに格納
  SavedUIDL.LoadFromFile('uidl.lst');
except
  // ファイルが読めない(存在しない?)
  try
    // 空のファイルを作成
    SavedUIDL.SaveToFile('uidl.lst');
  except
    ShowMessage('保存できません');
  end;
end;

だけでいいと思います。

最後に、新しいUIDLを「追加して」保存する処理は、
savedUidl.AddStrings(nowUidl);
try
  savedUidl.SaveToFile('uidl.lst');
except
  ShowMessage('保存できません');
end;
こんな感じです。
TStringListクラスの、AddStringsメソッドを見てください。


みけにゃん  URL  2002-11-05 23:36:57  No: 1917

この状態だと新しいUIDLを保存しているのか古いUIDLを保存しているかが
分からないのでこのような質問をしています。(>_<)

一応次の質問です。
一度受信したあと新規送信でメールを作って送信すれば新しいメールが
1通追加されてその新しいメールが受信されるはずなのに何も受信しないのは
どうしてなのでしょうか?>前からの通りUIDLの比較は行っています
また受信したメールのリスト(リストビュー)をクリックしたのですが
リストビューに表示された件名の内容とMemoに表示されるメールが
違うものになってしまうのはどうしてですか?


みけにゃん  URL  2002-11-06 00:37:23  No: 1918

>この状態だと新しいUIDLを保存しているのか古いUIDLを保存しているかが
>分からないのでこのような質問をしています。(>_<)

こちらは解決しましたが、次の質問〜は解決してない状態です。(>_<)


みけにゃん  URL  2002-11-06 01:30:39  No: 1919

次の問題点(質問)です。

>一度受信したあと新規送信でメールを作って送信すれば新しいメールが
>1通追加されてその新しいメールが受信されるはずなのに何も受信しないのは
>どうしてなのでしょうか?>前からの通りUIDLの比較は行っています
>
>また受信したメールのリスト(リストビュー)をクリックしたのですが
>リストビューに表示された件名の内容とMemoに表示されるメールが
>違うものになってしまうのはどうしてですか?


みけにゃん  URL  2002-11-06 01:46:38  No: 1920

>また受信したメールのリスト(リストビュー)をクリックしたのですが
>リストビューに表示された件名の内容とMemoに表示されるメールが
>違うものになってしまうのはどうしてですか?

この質問の追加情報なのですが、1つずつ件名と本文がずれて
表示されてしまっているようです。(実際の件数-1の本文が表示される)

一度受信すると新しいメールが来ても受信しないの方は
全然分からない(解決できない)状態です。(>_<)


みけにゃん  URL  2002-11-06 01:59:06  No: 1921

一番怪しいのはループの条件に使われているnowUidl.Count - 1だと
思うのですがにしのさんの書いてくださったコードには
for Count := 1 to nowUidl.Count - 1 doと書いてあるので
間違えじゃないと思っているのですがこれはどうなのですか?
>私の両方の質問

デバッグすると新しいメールが1件来てもCountの値は0(-1される)になるため
このループを抜けてしまうようです。また10件のメールが来ていても
9件しかメールを取り込むことが出来ないため一件ずれてしまうのかなぁって
思うのですが・・・。


やりすぎ  2002-11-06 02:31:50  No: 1922

>一番怪しいのはループの条件に使われているnowUidl.Count - 1だと
>思うのですがにしのさんの書いてくださったコードには
>for Count := 1 to nowUidl.Count - 1 doと書いてあるので
>間違えじゃないと思っているのですがこれはどうなのですか?

誰だって間違えることはある。
あくまでヒントとして考えなくては。
作っているのはあなたですよ。

>デバッグすると新しいメールが1件来てもCountの値は0(-1される)になるため
>このループを抜けてしまうようです。また10件のメールが来ていても
>9件しかメールを取り込むことが出来ないため一件ずれてしまうのかなぁって
>思うのですが・・・。

場所が特定されているんだったら、修正してやってみればいい


みけにゃん  URL  2002-11-06 02:35:30  No: 1923

ちなみにfor Count := 1 to nowUidl.Count doで行った所、リストの範囲を
超えるエラーが発生して止まってしまいました。


ふぅ  2002-11-06 02:54:17  No: 1924

nowUidl.Countを追加しているところを確認してみれば、間違いが発見できるんじゃないの?


みけにゃん  URL  2002-11-06 18:20:49  No: 1925

>nowUidl.Countを追加しているところを確認してみれば、間違いが発見できるんじゃないの?

あんまり見当がつかないです。(>_<)


ちゃんと考えた?  2002-11-06 18:46:13  No: 1926

文章が長過ぎて読む気になれないのではっきりしたことはいえないけど、
新着メールを確認するところが起動した時だけとかになってないのかな?


みけにゃん  URL  2002-11-06 18:53:10  No: 1927

>新着メールを確認するところが起動した時だけとかになってないのかな?

メールの受信を行っているのは起動時ではなくてメニューの受信か
ツールボタンの受信ボタンで行う以外は受信の作業は行っていません。
なので絶対に違うと思います。

ちゃんとした名前で投稿して欲しいかもです。
>やりすぎ&ちゃんと考えた?さん(同一人物?)


みけにゃん  URL  2002-11-06 20:27:11  No: 1928

昨日の最後の状態から一歩も抜け出せていないです。>最後に出した質問
この解決が出来たら次は本題のファイル化したメールを受信するには?に
入ることが出来そうです。

みなさんへ
文章は短くといって長々とコードを載せてしまうため毎回迷惑をかけちゃって
本当にごめんなさい。出来るだけ短くコードも掲載するように心がけます。


みけにゃん  URL  2002-11-06 20:34:35  No: 1929

for Count := 0 to NowUidl.Count - 1 doに変更したところ
リストにちゃんと全部のメールが表示されたのですが、にしのさんの
書いてくれたので合っていたのでしょうか?


にしの  2002-11-06 21:07:22  No: 1930

僕は神ではありませんよ…。
もう少し頭を柔らかくして考えてください。普通はわかると思うのですが。

僕もちょっと今回のことに書き込みすぎましたね。
少し興味のある分野だったので。
# この種のソフトを、ある程度作ったりもしましたし

今後はアドバイス程度にします。
最後に、「ファイル化したメールを表示するには?」についてだけ、アドバイス致します。
ざっと説明すると、まずTFileStreamを使って読み込み、ヘッダ本文を切り分け、本文をSJISに変換し、TStringListに納めます。
TFileStream,TStringListについてはヘルプを参照してください。
SJISに変換するには、NKF32.DLLというDLLがありますし、DelphiコンポーネントにもSJISに変換するものがあります。
ここはもう力業だけです。難しいところは1つもありません。
これがわからないのであれば、別のプログラミング言語を選ぶか、作成をあきらめた方がよいと思います。

以上で、僕はこの件から手を引きます。


みけにゃん  URL  2002-11-06 21:27:45  No: 1931

にしのさん本当に申し訳ありませんでした。(>_<)

ファイル化したデータなのですが、既に(nMail.dllによって)
Sift-JISに変換されているのですがこの場合はどうすれば良いのでしょうか?

VBやVC++でするとまたこの部分で悩んで長くなりそうなので
ここでがんばって完成まで行きたいと思っています。


みけにゃん  URL  2002-11-06 21:55:31  No: 1932

ごめんなさい、for Count := 0 to NowUidl.Count - 1 doで
うまくいったと思ったのですが、一度アプリケーションを終了すると
リストに入っていた件名等が消えてしまい新しいメールが来ても
1件しかメールが現れず、リストをクリックすると最初のメールが
メモに表示される事態になってしまいました。

アプリケーション終了時にリストの内容を保存して、起動時に読み込む
のに使うおくのはやはりTStringListが良いのでしょうか?
また他のやり方があるのでしょうか?


みけにゃん  2002-11-06 23:08:48  No: 1933

下記の事と上記の事、誰かアドバイスだけでよろしいのでお願いします。(>_<)

#選択されたListItemのDataにファイル名があるので、それを読み込みます。

上記の事を試そうとしているのですが、ファイル名が入っていないようで
毎回AccessViolationの例外が発生します。これはどうしてですか?

Listをクリックしたらファイルを読み込むのコードはシンプルにヘッダも
付いたファイルをMemoに読み込むと言うもので以下のコードです。
BodyMemo.Lines.LoadFromFile(String(MailData.Data^));


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加