Page 1 of 3

Indy and Android

PostPosted: Fri May 27, 2016 6:59 am
by Lena
I deployed my application with the sqllite database on the mobile device.
The database is located on this path:
Code: Select all
void __fastcall TForm1::FDConnection1BeforeConnect(TObject *Sender)
{
 #if defined(_PLAT_IOS) || defined(_PLAT_ANDROID)
 FDConnection1->Params->Values["Database"] =
 System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "mikros.s3db");
 #endif
}


I want to add a button to my application by clicking on which I could send the database mikros.s3db to correct email.
Is that possible?

Re: Indy and Android

PostPosted: Fri May 27, 2016 5:38 pm
by rlebeau
Lena wrote:I want to add a button to my application by clicking on which I could send the database mikros.s3db to correct email.
Is that possible?


Indy implements the SMTP protocol for sending emails (the TIdSMTP componet). So your app would have to configure it with an external SMTP server (GMail, Yahoo, etc) and user account authentication so your mobile app can connect to it. Different servers have different requirements about authentication, encryption, etc.

Indy does not have any integration with any iOS/Android native email APIs for sending emails with a mobile device's own email setups.

Re: Indy and Android

PostPosted: Sat May 28, 2016 4:39 am
by Lena
Thank you.
Can you show me link with c++ example TIdSMTP + GMail + Android + attachment?

Re: Indy and Android

PostPosted: Sun May 29, 2016 2:56 pm
by rlebeau
Lena wrote:Thank you.
Can you show me link with c++ example TIdSMTP + GMail + Android + attachment?


There are plenty of TIdSMTP examples floating around online if you search around. And there are even several discussions on this same BCBJ forum related to TIdSMTP.

On Android, it is probably best not to use SMTP directly, though. The user is likely to expect using an email account already installed on the device. So you should trigger an Android ACTION_SENDTO Intent containing your email data, and let Android prompt the user which email app+account to send the email with.

Re: Indy and Android

PostPosted: Sun May 29, 2016 9:37 pm
by Lena
Today I try TIdSMTP for Windows. No problem.
Which files for Android app I must download from this page: http://indy.fulgan.com/SSL/
AndroidOpenssl1.0.1t.zip
AndroidOpenssl1.0.2h.zip
OpenSSL 1.0.2g Android.zip
?
How correct add this files in Android app just Add->To project libssl.so and libcrypto.so ?

So you should trigger an Android ACTION_SENDTO


I find it hard to use intent, because there are no examples in C++

Re: Indy and Android

PostPosted: Mon May 30, 2016 10:29 am
by rlebeau
Lena wrote:Which files for Android app I must download from this page: http://indy.fulgan.com/SSL/
AndroidOpenssl1.0.1t.zip
AndroidOpenssl1.0.2h.zip
OpenSSL 1.0.2g Android.zip
?


Use the latest version.

Lena wrote:How correct add this files in Android app just Add->To project libssl.so and libcrypto.so ?


https://forums.embarcadero.com/message. ... eID=825670

1. Add the 2 .so files to your project deployment and set them to deploy to the .\assets\internal\ folder

2. add the System.StartupCopy unit as the first unit in your DPR's uses clause.

3. call IdOpenSSLSetLibPath(TPath.GetDocumentsPath) at app startup.


Lena wrote:I find it hard to use intent, because there are no examples in C++


There have been C++ examples posted in the Embarcadero forums. Such as:

https://forums.embarcadero.com/thread.j ... dID=118338

Re: Indy and Android

PostPosted: Tue May 31, 2016 5:16 am
by Lena
Using OpenSSL with Indy

My first step
Code: Select all
#include <System.StartupCopy.hpp>
#include <IdSSLOpenSSLHeaders.hpp>
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 IdOpenSSLSetLibPath(System::Ioutils::TPath::GetDocumentsPath());
}


Do I need use TidAntiFreeze when I use TIdSMTP in Andoid app?
С++ Builder Berlin.

P.S.
Oops no component TidAntiFreeze in С++ Builder Berlin.

Re: Indy and Android

PostPosted: Tue May 31, 2016 6:33 am
by Lena
In Android I have problem with encoding TIdMessage Subject. I got ???? ?????

Re: Indy and Android

PostPosted: Tue May 31, 2016 7:09 am
by Lena
I can't send email from code.
In Edit2->Text I type the word tracklogic
Code: Select all
      IdMessage1->Body->Text = L"От: " + Edit2->Text;
      IdMessage1->Recipients->Add();
      IdMessage1->Recipients->Items[0]->Address = Edit2->Text + L"@yandex.ru";
      IdMessage1->Recipients->Items[0]->Domain = L"yandex.ru";
      IdMessage1->Recipients->Items[0]->Text = Edit2->Text + L"@yandex.ru";
      IdMessage1->Recipients->Items[0]->User =  Edit2->Text;
      IdSMTP1->Connect();
      IdSMTP1->Send(IdMessage1);
      IdMessage1->Recipients->Clear();



<????@yandex.ru>: host 127.0.0.1[127.0.0.1] said: 554 5.1.1 Unknown user;
k2DlsLiJ (in reply to end of DATA command)

Delivery status:

Reporting-MTA: dns; mxback5o.mail.yandex.net
X-Yandex-Queue-ID: 1647536A009C
X-Yandex-Sender: rfc822; vlad44b@yandex.ru
Arrival-Date: Tue, 31 May 2016 16:03:32 +0300 (MSK)

Final-Recipient: rfc822; ????@yandex.ru
Original-Recipient: rfc822;????@yandex.ru
Action: failed
Status: 5.1.1
Remote-MTA: dns; 127.0.0.1
Diagnostic-Code: smtp; 554 5.1.1 Unknown user; k2DlsLiJ

Re: Indy and Android

PostPosted: Tue May 31, 2016 5:22 pm
by rlebeau
Lena wrote:
Code: Select all
#include <System.StartupCopy.hpp>



Not sure if this is actually needed (I haven't looked at it yet), but you might need this, too:

Code: Select all
#pragma link "System.StartupCopy"


Lena wrote:
Code: Select all
void __fastcall TForm1::FormCreate(TObject *Sender)



You should NEVER use the OnCreate event in C++. Use the actual constructor instead.

Lena wrote:Do I need use TidAntiFreeze when I use TIdSMTP in Andoid app?


Honestly, I don't know how well (if at all) TIdAntiFreeze works cross-platform. But either way, you are not supposed to block the main UI thread anyway. You should use TIdSMTP in its own worker thread instead.

Lena wrote:Oops no component TidAntiFreeze in С++ Builder Berlin.


There is a design flaw in how Indy packages TIdAntiFreeze that causes issues, so TIdAntiFreeze is disabled in the IDE for FireMonkey projects. But you can still create an instance of TIdAntiFreeze in code at runtime instead, and it will function the same as if you had dropped it on a Form at design-time.

Re: Indy and Android

PostPosted: Tue May 31, 2016 5:23 pm
by rlebeau
Lena wrote:In Android I have problem with encoding TIdMessage Subject. I got ???? ?????


To specify a charset used for encoding an email's top-level headers, like Subject, you have to use the TIdMessage::OnInitializeISO event, not the TIdMessage::Charset property (message parts have their own local Charset property instead). In Delphi/C++Builder 2009+, Indy uses UTF-8 by default, you should stick with that. For Russian/Cyrillic, you could use KOI8-R if not UTF-8, but I would not suggest using Windows-1251 either way.

Re: Indy and Android

PostPosted: Tue May 31, 2016 5:34 pm
by rlebeau
Lena wrote:In Edit2->Text I type the word tracklogic
...
<????@yandex.ru>: host 127.0.0.1[127.0.0.1] said: 554 5.1.1 Unknown user;
k2DlsLiJ (in reply to end of DATA command)


I could see that happening if Edit2->Text contained non-ASCII characters, but there is no way it could be converting "tracklogic" to "????", and certainly not with the code you have shown. There is no way it could even go from 10 ASCII characters to 4 '?' characters anyway.

BTW, Recipients->Add() returns a TIdEmailAddressItem*, so you don't need to index into Recipients->Items[0] for each sub-property value. And there is no reason to use the Address or Text property if you are using the User and Domain properties, and vice versa. So, use either:

Code: Select all
TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
Item->Address = Edit2->Text + L"@yandex.ru";


Code: Select all
TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
Item->Text = L"<" + Edit2->Text + L"@yandex.ru>";


Code: Select all
TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
Item->User = Edit2->Text;
Item->Domain = L"yandex.ru";

Re: Indy and Android

PostPosted: Wed Jun 01, 2016 1:02 am
by Lena
like Subject, you have to use the TIdMessage::OnInitializeISO event

For Russian/Cyrillic, you could use KOI8-R if not UTF-8, but I would not suggest using Windows-1251 either way.


How to use OnInitializeISO?
Code: Select all
void __fastcall TFormServis::IdMessage1InitializeISO(System::WideChar &VHeaderEncoding,
        UnicodeString &VCharSet)
{
  VHeaderEncoding = 'B'; //In Subject got ??????

  //I try KOI8-R or UTF-8 or windows-1251 for VCharSet but got in body ??????
  //VCharSet = L"KOI8-R";

  //only correct body when set in object inspectot:
  //CharSet=windows-1251
}


I try to use SysLocale.PriLangID russian forum
SysLocale.PriLangID = LANG_RUSSIAN;
But: use of undeclared identifier 'LANG_RUSSIAN'

I could see that happening if Edit2->Text contained non-ASCII characters, but there is no way it could be converting "tracklogic" to "????", and certainly not with the code you have shown.


Thank you. It my mistake I must use Edit3 not Edit2.:)

All my code now:
Code: Select all
  try
  {
    try
      {
      //CharSet=windows-1251 in object inspectot and all good for Body
      IdMessage1->Body->Text = L"От: " + Edit2->Text;
//SysLocale.PriLangID = LANG_RUSSIAN; error
      //here problem Subject=???????
      IdMessage1->Subject = L"База данных 1"; //<- test

      TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
      Item->User = Edit3->Text;
      Item->Domain = L"yandex.ru";
      /*
      #if defined(_PLAT_IOS) || defined(_PLAT_ANDROID)
       String att = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath
       (), "mikros.s3db");
      #endif

      //TO DO: I have not yet solved the problem with attachment:
      std::unique_ptr<TIdAttachmentFile> attachment(new TIdAttachmentFile(IdMessage1->MessageParts, att));
      */
      Button3->Enabled = false;
      IdSMTP1->Connect();
      IdSMTP1->Send(IdMessage1);
      Button3->Enabled = true;
      //***in Android for MessageDlg****
         struct TCloseDialogHandler : public TCppInterfacedObject<TInputCloseDialogProc>
         {
         void __fastcall Invoke(const System::Uitypes::TModalResult AResult)
           {
            switch (AResult)
            {
               case mrYes :
                {
                 //Application->Terminate();
                 //ShowMessage("You chose Yes");
                }
               break;
               case mrNo:
                ShowMessage("You chose No");
               break;
               case mrCancel:
                ShowMessage("You chose Cancel");
               break;
            }
           }
         };

         _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
         String MES = (L"Письмо отправлено.");
         MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
         //*****end MessageDlg***
      }
      catch (EIdException &E)
      {
         //*******
         struct TCloseDialogHandler : public TCppInterfacedObject<TInputCloseDialogProc>
         {
         void __fastcall Invoke(const System::Uitypes::TModalResult AResult)
           {
            switch (AResult)
            {
               case mrYes :
                {
                 //Application->Terminate();
                 //ShowMessage("You chose Yes");
                }
               break;
               case mrNo:
                ShowMessage("You chose No");
               break;
               case mrCancel:
                ShowMessage("You chose Cancel");
               break;
            }
           }
         };

         _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
         String MES = (L"Problem. " + E.Message);
         MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
         //********
      }

  }
  __finally
       {
        Button3->Enabled = true;
        if(IdSMTP1->Connected())
          {
           IdSMTP1->Disconnect();
           }
       }

Re: Indy and Android

PostPosted: Wed Jun 01, 2016 12:22 pm
by rlebeau
Lena wrote:How to use OnInitializeISO?


Set the VCharset parameter to the desired charset (UTF-8, KOI8-R, Windows-1251, etc), and set the VHeaderEncoding parameter to the desired byte encoding (B = Base64, Q = QuotedPrintable, 8 = 8bit Binary).

Code: Select all
void __fastcall TFormServis::IdMessage1InitializeISO(System::WideChar &VHeaderEncoding,
        UnicodeString &VCharSet)
{
   VCharSet = L"UTF-8";
   VHeaderEncoding = L'B';
}


Code: Select all
void __fastcall TFormServis::IdMessage1InitializeISO(System::WideChar &VHeaderEncoding,
        UnicodeString &VCharSet)
{
   VCharSet = L"Windows-1251";
   VHeaderEncoding = L'Q';
}


Lena wrote:I try to use SysLocale.PriLangID russian forum
SysLocale.PriLangID = LANG_RUSSIAN;
But: use of undeclared identifier 'LANG_RUSSIAN'


That is a Windows-specific constant. It is defined in winnt.h, which is included by windows.h. You can't use Windows LANGIDs in Android, and besides the SysLocale.PriLangID field is not even used on non-Windows platforms.

Even if it were used, setting SysLocale.PriLangID to LANG_RUSSIAN causes the TIdMessage::OnInitializeISO event to default the charset to KOI8-R (LANG_UKRAINIAN defaults to Windows-1251). If you set the charset explicitly instead, you don't need to set SysLocale.PriLangID at all.

Lena wrote:All my code now


Try something like this:

Code: Select all
void __fastcall TFormServis::IdMessage1InitializeISO(System::WideChar &VHeaderEncoding,
        UnicodeString &VCharSet)
{
   VCharSet = L"UTF-8";
   VHeaderEncoding = L'B';
}

...

//***in Android for MessageDlg****
struct TCloseDialogHandler : public TCppInterfacedObject<TInputCloseDialogProc>
{
   void __fastcall Invoke(const System::Uitypes::TModalResult AResult)
   {
      switch (AResult)
      {
         case mrYes :
         {
            //Application->Terminate();
            //ShowMessage("You chose Yes");
            break;
         }

         case mrNo:
            ShowMessage("You chose No");
            break;

         case mrCancel:
            ShowMessage("You chose Cancel");
            break;
      }
   }
};

...

Button3->Enabled = false;
try
{
   try
   {
      IdMessage1->Clear();
      IdMessage1->Subject = L"База данных 1"; //<- test

      TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
      Item->User = Edit3->Text;
      Item->Domain = L"yandex.ru";

      #if defined(_PLAT_IOS) || defined(_PLAT_ANDROID)

      TIdText *text = new TIdText(IdMessage1->MessageParts);
      text->Body->Text = L"От: " + Edit2->Text;
      text->ContentType = L"text/plain";
      text->CharSet = L"utf-8";

      String att = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), L"mikros.s3db");
      TIdAttachmentFile *attachment = new TIdAttachmentFile(IdMessage1->MessageParts, att);

      IdMessage1->ContentType = L"multipart/mixed";

      #else

      IdMessage1->Body->Text = L"От: " + Edit2->Text;
      IdMessage1->ContentType = L"text/plain";
      IdMessage1->CharSet = L"utf-8";

      #endif

      IdSMTP1->Connect();
      try {
         IdSMTP1->Send(IdMessage1);
      }
      __finally {
         IdSMTP1->Disconnect();
      }

      _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
      String MES = L"Письмо отправлено.";
      MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
   }
   catch (const Exception &E)
   {
      _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
      String MES = L"Problem. " + E.Message;
      MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
   }
}
__finally
{
   Button3->Enabled = true;
}


Alternatively, use TIdMessageBuilderPlain to help you prepare the TIdMessage parts:

Code: Select all
void __fastcall TFormServis::IdMessage1InitializeISO(System::WideChar &VHeaderEncoding,
        UnicodeString &VCharSet)
{
   VCharSet = L"UTF-8";
   VHeaderEncoding = L'B';
}

...

//***in Android for MessageDlg****
struct TCloseDialogHandler : public TCppInterfacedObject<TInputCloseDialogProc>
{
   void __fastcall Invoke(const System::Uitypes::TModalResult AResult)
   {
      switch (AResult)
      {
         case mrYes :
         {
            //Application->Terminate();
            //ShowMessage("You chose Yes");
            break;
         }

         case mrNo:
            ShowMessage("You chose No");
            break;

         case mrCancel:
            ShowMessage("You chose Cancel");
            break;
      }
   }
};

...

Button3->Enabled = false;
try
{
   try
   {
      IdMessage1->Clear();
      IdMessage1->Subject = L"База данных 1"; //<- test

      TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
      Item->User = Edit3->Text;
      Item->Domain = L"yandex.ru";

      std::unique_ptr<TIdMessageBuilderPlain> builder(new TIdMessageBuilderPlain);

      builder->PlainText->Text = L"От: " + Edit2->Text;
      builder->PlaintTextCharSet = L"utf-8";
      builder->PlainTextContentTransfer = L"binary";

      #if defined(_PLAT_IOS) || defined(_PLAT_ANDROID)

      String att = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), L"mikros.s3db");
      builder->Attachments->Add(att);

      #endif

      builder->FillMessage(IdMessage1);

      IdSMTP1->Connect();
      try {
         IdSMTP1->Send(IdMessage1);
      }
      __finally {
         IdSMTP1->Disconnect();
      }

      _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
      String MES = L"Письмо отправлено.";
      MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
   }
   catch (const Exception &E)
   {
      _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
      String MES = L"Problem. " + E.Message;
      MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
   }
}
__finally
{
   Button3->Enabled = true;
}

Re: Indy and Android

PostPosted: Wed Jun 01, 2016 2:21 pm
by Lena
Thank you!
I try your code:
Code: Select all
void __fastcall TFormServis::IdMessage1InitializeISO(System::WideChar &VHeaderEncoding,
        UnicodeString &VCharSet)
{
   VCharSet = L"UTF-8";
   VHeaderEncoding = L'B';
}

Code: Select all
Button3->Enabled = false;
    try
   {
       try
       {
          IdMessage1->Clear();
        IdMessage1->Subject = L"Привет мир Hello word"; //<- mix RU+EN

          TIdEMailAddressItem *Item = IdMessage1->Recipients->Add();
          Item->User = Edit3->Text;
          Item->Domain = L"yandex.ru";

          #if defined(_PLAT_IOS) || defined(_PLAT_ANDROID)

        //#include "IdText.hpp"
        //Error: no matching constructor for initialization of 'Idtext::TIdText'
        //I am add NULL in constructor. Is it correct?
        TIdText *text = new TIdText(IdMessage1->MessageParts,NULL);
        text->Body->Text = L"От: " + Edit2->Text;
          text->ContentType = L"text/plain";
          text->CharSet = L"utf-8";

          String att = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), L"mikros.s3db");
          TIdAttachmentFile *attachment = new TIdAttachmentFile(IdMessage1->MessageParts, att);

          IdMessage1->ContentType = L"multipart/mixed";

          #else

          IdMessage1->Body->Text = L"От: " + Edit2->Text;
          IdMessage1->ContentType = L"text/plain";
          IdMessage1->CharSet = L"utf-8";

          #endif

          IdSMTP1->Connect();
          try {
             IdSMTP1->Send(IdMessage1);
          }
          __finally {
             IdSMTP1->Disconnect();
          }

          _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
          String MES = L"Письмо отправлено.";
          MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
       }
       catch (const Exception &E)
       {
          _di_TInputCloseDialogProc handler = new TCloseDialogHandler();
          String MES = L"Problem. " + E.Message;
          MessageDlg(MES, TMsgDlgType::mtInformation,   TMsgDlgButtons() << TMsgDlgBtn::mbYes, 0, handler);
       }
    }
    __finally
    {
       Button3->Enabled = true;
    }



However, I got a strange error :(