Модераторы: Snowy, Poseidon, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Отправка почты через WSA 
:(
    Опции темы
Akella
Дата 24.5.2005, 08:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 4
Всего: 329



Код

unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, winsock, StdCtrls;

type
  TTCPClientForm = class(TForm)
    btSend: TButton;
    edServer: TEdit;
    Label1: TLabel;
    mmLog: TMemo;
    Label2: TLabel;
    Label3: TLabel;
    edPort: TEdit;
    Label4: TLabel;
    edSendTo: TEdit;
    mmMessage: TMemo;
    Label5: TLabel;
    Label6: TLabel;
    edFile: TEdit;
    procedure btSendClick(Sender: TObject);
  private
    { Private declarations }
    sServerListen : TSOCKET;
  public
    { Public declarations }
  end;

const
  _Code64: string[64]=('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
  

var
  TCPClientForm: TTCPClientForm;

implementation

{$R *.dfm}

procedure TestWinSockError(S:String);
var
 iErr:Integer;
 sFullErr:String;
begin
 sFullErr:='Неизвестная ошибка';
 iErr:=WSAGetLastError();

 case iErr of
  WSANOTINITIALISED: sFullErr:='Нужно сначала вызвать функцию WSASturtup, а потом создавать сокет';
    WSAENETDOWN: sFullErr:='Cвязь нарушена, возможные причины - отошёл кабель или отключились от Интернета';
    WSAEADDRINUSE: sFullErr:='Указанный адрес уже используется';
    WSAEFAULT: sFullErr:='Параметры name и namelen не соответствуют выбранной адресации. Параметр namelen может быть меньше необходимого значения, а name содержать некорректные данные';
    WSAEINPROGRESS: sFullErr:='Выполняется операция в блокирующем режиме. Вы уже запустили на выполнение какую-то функцию и нужно дождаться завершения её работы';
    WSAEINVAL: sFullErr:='Сокет уже связан с адресом';
    WSAENOBUFS: sFullErr:='Недостаточно буферов, слишком много соединений';
    WSAENOTSOCK: sFullErr:='Неверный дескриптор сокета';
  WSAEISCONN: sFullErr:='Сокет уже подключён';
  WSAEMFILE: sFullErr:='Нет больше доступных дескрипторов';
 end;

 MessageBox(0, PChar('Ошибка в функции '+S+' - '+sFullErr), 'Ошибка', 0);
end;

function TestFuncError(iErr:Integer; FuncName:String):Boolean;
begin
 Result:=false;
 if iErr = SOCKET_ERROR then
  begin
   TestWinSockError(FuncName);
   Result:=true;
  end;
end;

function LookupName(name:String): TInAddr;
var
 HostEnt: PHostEnt;
 InAddr: TInAddr;
begin
 if name[4]='.' then
  InAddr.s_addr := inet_addr(PChar(name))
 else
  begin
  HostEnt := gethostbyname(PChar(name));
  FillChar(InAddr, SizeOf(InAddr), 0);
  if HostEnt <> nil then
   begin
    with InAddr, HostEnt^ do
     begin
      S_un_b.s_b1 := h_addr^[0];
      S_un_b.s_b2 := h_addr^[1];
      S_un_b.s_b3 := h_addr^[2];
      S_un_b.s_b4 := h_addr^[3];
     end;
   end
  end;
  Result := InAddr;
end;

function GetLocalHost: string;
var
 sh : array [0..255] of char;
begin
 if gethostname(sh, 255)=0 then
  Result := StrPas(sh)
 else
  Result := '';
end;

procedure SendStr(s:TSocket; str:String);
var
 sRecvBuff : array [0..255] of char;
 TempStr : AnsiString;
begin
 TempStr:=str+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(s, sRecvBuff, Length(TempStr), 0), 'Send Attachment');
 TCPClientForm.mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));
end;

procedure Base64Send(FileName: string);
var
 afile: File;
 i:     longint;
 quads: integer;
 b:     array[0..2279] of byte;
 j,k,l,m:integer;
 stream:string[76];
begin
 AssignFile(afile,filename);
 Reset(afile,1);
 SendStr(TCPClientForm.sServerListen, '--========sdfgsagg======');
 SendStr(TCPClientForm.sServerListen, 'Content-Type: application/octet-stream; name="'+ExtractFileName(FileName)+'"');
 SendStr(TCPClientForm.sServerListen, 'Content-Transfer-Encoding: base64');
 SendStr(TCPClientForm.sServerListen, 'Content-Disposition: attachment; filename="'+ExtractFileName(FileName)+'"');
 SendStr(TCPClientForm.sServerListen, 'Content-Description: attachment');
 SendStr(TCPClientForm.sServerListen, '');
 stream:='';
 quads:=0;
 j:=Filesize(afile) div 2280;
 for i:=1 to j do
  begin
   BlockRead(afile,b,2280);
   for m:=0 to 39 do
    begin
     for k:=0 to 18 do
      begin
       l:=57*m+3*k;
       stream[quads+1]:=_Code64[(b[l]div 4)+1];
       stream[quads+2]:=_Code64[(b[l] mod 4)*16 +(b[l+1] div 16)+1];
       stream[quads+3]:=_Code64[(b[l+1] mod 16)*4 +(b[l+2] div 64)+1];
       stream[quads+4]:=_Code64[b[l+2] mod 64+1];
       Inc(quads,4);

       if quads=76 then
        begin
         stream[0]:=#76;
         SendStr(TCPClientForm.sServerListen, stream);
         quads:=0;
        end;
      end;
    end;
  end;

 j:=(Filesize(afile) mod 2280) div 3;

 for i:=1 to j do
  begin
   BlockRead(afile,b,3);
   stream[quads+1]:=_Code64[(b[0]div 4)+1];
   stream[quads+2]:=_Code64[(b[0] mod 4)*16 +(b[1] div 16)+1];
   stream[quads+3]:=_Code64[(b[1] mod 16)*4 +(b[2] div 64)+1];
   stream[quads+4]:=_Code64[b[2] mod 64+1];
   Inc(quads,4);

   if quads=76 then
    begin
     stream[0]:=#76;
     SendStr(TCPClientForm.sServerListen, stream);
     quads:=0;
    end;
  end;

 if (Filesize(afile) mod 3) = 2 then
  begin
   BlockRead(afile,b,2);
   stream[quads+1]:=_Code64[(b[0]div 4)+1];
   stream[quads+2]:=_Code64[(b[0] mod 4)*16 +(b[1] div 16)+1];
   stream[quads+3]:=_Code64[(b[1] mod 16)*4 +1];
   stream[quads+4]:='=';
   Inc(quads,4);
  end;

 if (Filesize(afile) mod 3) = 1 then
  begin
   BlockRead(afile,b,1);
   stream[quads+1]:=_Code64[(b[0]div 4)+1];
   stream[quads+2]:=_Code64[(b[0] mod 4)*16 +1];
   stream[quads+3]:='=';
   stream[quads+4]:='=';
   Inc(quads,4);
  end;
 stream[0]:=Chr(quads);

 if quads>0 then
  SendStr(TCPClientForm.sServerListen, stream);

 CloseFile(afile);
end;

procedure TTCPClientForm.btSendClick(Sender: TObject);
var
 wData : WSADATA;
 server_addr : sockaddr_in;
 sRecvBuff : array [0..255] of char;
 TempStr : AnsiString;
 i, iRet : Integer;
begin
 mmLog.Clear;

 // Загрузка WinSock
 if WSAStartup(MAKEWORD(1,1), wData) <> 0 then
    begin
   MessageBox(0, 'Не могу загрузить WinSock', 'Ошибка', 0);
   exit;
    end;

 // Создание сокета
 sServerListen := socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
 if sServerListen = INVALID_SOCKET then
  begin
   MessageBox(0, 'Ошибка создания сокета', 'Ошибка', 0);
   exit;
  end;

 // Запонение структуры адреса
 server_addr.sin_addr.s_addr := htonl(INADDR_ANY);
 server_addr.sin_family := AF_INET;
 server_addr.sin_port := htons(StrToInt(edPort.Text));
 server_addr.sin_addr := LookupName(edServer.Text);

 if (connect(sServerListen, server_addr, sizeof(server_addr)) = SOCKET_ERROR) then
  begin
   TestWinSockError('Connect');
   exit;
  end;

 TestFuncError(recv(sServerListen, sRecvBuff, 1024, 0), 'Ошибка приветствия');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 // Заприветствуем сервер
 TempStr:='HELO '+GetLocalHost+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send HELO');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 TestFuncError(recv(sServerListen, sRecvBuff, SizeOf(sRecvBuff), 0), 'Ошибка приветствия');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 // Скажем от кого письмецо
 TempStr:='MAIL FROM:<[email protected]>'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send MAIL FROM');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 TestFuncError(recv(sServerListen, sRecvBuff, SizeOf(sRecvBuff), 0), 'Ошибка адресата');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 // Скажем для кого письмецо
 TempStr:='RCPT TO:<'+edSendTo.Text+'>'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send MAIL TO');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 TestFuncError(recv(sServerListen, sRecvBuff, SizeOf(sRecvBuff), 0), 'Ошибка получателя');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 // Начало отправки данных
 TempStr:='DATA'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send DATA');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 TestFuncError(recv(sServerListen, sRecvBuff, SizeOf(sRecvBuff), 0), 'Ошибка начала данных');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 ////////////////////
 //Заголовок
 /////////////////////
 // Для
 TempStr:='From:<[email protected]>'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send MAIL FROM');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 // От
 TempStr:='To:<'+edSendTo.Text+'>'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send MAIL TO');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 // Кодировка
 SendStr(sServerListen, 'Mime-Version: 1.0');
 SendStr(sServerListen, 'Content-Type: multipart/mixed;');
 SendStr(sServerListen, '        boundary="========sdfgsagg======"');

 SendStr(sServerListen, '');
 SendStr(sServerListen, '--========sdfgsagg======');
 SendStr(sServerListen, 'Content-Type: text/plain; charset="us-ascii"');
 SendStr(sServerListen, '');

 //Отправка текста письма
 for i:=0 to mmMessage.Lines.Count-1 do
  begin
   // Сообщение
   TempStr:=mmMessage.Lines[i]+#13+#10;
   while TempStr<>'' do
    begin
     CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
     iRet:=send(sServerListen, sRecvBuff, Length(TempStr), 0);

     if iRet=SOCKET_ERROR then
      break;

     mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

     Delete(TempStr, 1, iRet);
    end;
  end;

 //Отправка эттача
 SendStr(sServerListen, '');
 if edFile.Text<>'' then
  Base64Send(edFile.Text);

 // Конец сообщения
 TempStr:=#13+#10+'.'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send .');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 TestFuncError(recv(sServerListen, sRecvBuff, SizeOf(sRecvBuff), 0), 'Ошибка конца сообщения');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 // Выход
 TempStr:='QUIT'+#13+#10;
 CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
 TestFuncError(send(sServerListen, sRecvBuff, Length(TempStr), 0), 'Send QUIT');
 mmLog.Lines.Add('>'+Copy(TempStr, 1, Pos(#13, TempStr)));

 TestFuncError(recv(sServerListen, sRecvBuff, SizeOf(sRecvBuff), 0), 'Ошибка выхода');
 TempStr:=sRecvBuff;
 mmLog.Lines.Add('<'+Copy(TempStr, 1, Pos(#13, TempStr)));
 Application.ProcessMessages;

 CloseSocket(sServerListen);
end;

end.

PM MAIL   Вверх
Akella
Дата 24.5.2005, 08:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 4
Всего: 329



Нужно дополнить код так, чтобы можно было присоединять не один а несколько файлов

Присоединённый файл ( Кол-во скачиваний: 20 )
Присоединённый файл  111.JPG
PM MAIL   Вверх
Rouse_
Дата 24.5.2005, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 469
Регистрация: 23.4.2005

Репутация: 5
Всего: 29



по поводу function LookupName(name:String): TInAddr;

сделай лучше что-то наподобие такого:

Код

    InAddr := inet_addr(PChar(FAddress));
    if InAddr = INADDR_NONE then
    begin
      Host := gethostbyname(PChar(FAddress));
      if not Assigned(Host) then
      begin
        Error(WSAGetLastError);
        Exit;
      end;
      InAddr := PInAddr(Host.h_addr_list^)^.S_addr;
    end;



--------------------
 Vae Victis
(Горе побежденным (лат.))
Демо с открытым кодом: http://rouse.drkb.ru 
PM MAIL WWW ICQ   Вверх
Akella
Дата 24.5.2005, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 4
Всего: 329



объясни, почему

Это сообщение отредактировал(а) dsergey - 24.5.2005, 13:14
PM MAIL   Вверх
Rouse_
Дата 24.5.2005, 13:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 469
Регистрация: 23.4.2005

Репутация: 5
Всего: 29



Потому что if name[4]='.' then не сработает на адресе 12.0.0.10 к примеру...

логика моего алгоритма такова.

Предполагаем что нам передан IP адрес. Преобразуем его через inet_addr.
Если не получилось, результат преобразования будет INADDR_NONE. Тогда предполагаем, что у нас введено DNS (или UNC имя)...
Тут уже проиходит получение IP адреса через gethostbyname.
Если и теперь не получили, то значит передано нам черти знает что...

Ну а вот это:
Код

    with InAddr, HostEnt^ do
     begin
      S_un_b.s_b1 := h_addr^[0];
      S_un_b.s_b2 := h_addr^[1];
      S_un_b.s_b3 := h_addr^[2];
      S_un_b.s_b4 := h_addr^[3];
     end;

Гораздо быстрее делается вот таким образом:
Код

InAddr := PInAddr(Host.h_addr_list^)^.S_addr;

1 операция вместо 4-х


--------------------
 Vae Victis
(Горе побежденным (лат.))
Демо с открытым кодом: http://rouse.drkb.ru 
PM MAIL WWW ICQ   Вверх
Akella
Дата 24.5.2005, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 4
Всего: 329



Так как же всё-таки прикрепить 2 или 10 файлов?
PM MAIL   Вверх
Rouse_
Дата 24.5.2005, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 469
Регистрация: 23.4.2005

Репутация: 5
Всего: 29



Вот тут почитай... http://rfc.sunsite.dk/rfc/rfc1521.html
Ну а вообще перед отправкой следующего аттача разделяй их CRLF

Вот тебе примерчик с двумя аттачами:

Код

Date: Tue, 24 May 2005 17:02:31 +0400
From: Alexander Bagel <[email protected]>
X-Mailer: The Bat! (v2.04.7)
Reply-To: Alexander Bagel <[email protected]>
Organization: =?Windows-1251?B?1uXt8vAgw/Dg7eQ=?=
X-Priority: 3 (Normal)
Message-ID: <[email protected]>
To: [email protected]
Subject: test
MIME-Version: 1.0
Content-Type: multipart/mixed;
 boundary="----------D0DF1092CDF3DAF"

------------D0DF1092CDF3DAF
Content-Type: text/plain; charset=Windows-1251
Content-Transfer-Encoding: 8bit

Hello ,

  

-- 
Best regards,
 Alexander                          mailto:[email protected]
------------D0DF1092CDF3DAF
Content-Type: text/plain; name="2.txt"
Content-transfer-encoding: base64
Content-Disposition: attachment; filename="2.txt"

//4SBEIEPgRABD4EOQQgAEIENQRBBEIEPgQyBEsEOQQgADAEQgRCBDAERwQ=

------------D0DF1092CDF3DAF
Content-Type: text/plain; name="1.txt"
Content-transfer-encoding: base64
Content-Disposition: attachment; filename="1.txt"

//4fBDUEQAQyBEsEOQQgAEIENQRBBEIEPgQyBEsEOQQgADAEQgRCBDAERwQ=

------------D0DF1092CDF3DAF--


Это сообщение отредактировал(а) Rouse_ - 24.5.2005, 16:00


--------------------
 Vae Victis
(Горе побежденным (лат.))
Демо с открытым кодом: http://rouse.drkb.ru 
PM MAIL WWW ICQ   Вверх
Akella
Дата 25.5.2005, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 4
Всего: 329



smile
PM MAIL   Вверх
Rouse_
Дата 25.5.2005, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 469
Регистрация: 23.4.2005

Репутация: 5
Всего: 29



Я ж тебе дал пример. Пределай алгоритм чтобы на выходе получался вот такой текст примерно.
Т.е. все части письма разделены при помощи boundary="----------D0DF1092CDF3DAF" и Content-Type должен быть multipart/mixed;


--------------------
 Vae Victis
(Горе побежденным (лат.))
Демо с открытым кодом: http://rouse.drkb.ru 
PM MAIL WWW ICQ   Вверх
Akella
Дата 25.5.2005, 15:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 4
Всего: 329



Цитата(Rouse_ @ 25.5.2005, 14:54)
и Content-Type должен быть multipart/mixed;

это не понял
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.2183 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.