Hi,
Dave, thanks for your feedback. I am aware of the Initialize()
command you pointed out (read over those docs lots of times!) and do use it to
make sure the thread isn’t a problem. I have pasted the function here for
reading purposes, the project has too many pieces to put together and attach (libs
etc.) so this should be somewhat easier. The DoPOP3() is called right now after
a button is clicked on the window, eventually when its working it will be automated
etc.
Here is a code example:
void SaleMonitorWindow::DoPOP3MailCheck(void)
{
// This is where the magic is done to check the email
account
char WorkString[4096]; char
TempWord[4096];
char BufferString[4096];
uLong ReadCount = 0;
wxSocketBase::Initialize();
// Needed because we are in a multi-thread
environment
wxIPV4address
addr;
Dexter.StringPrint(WorkString,
"%s",
Dexter.XMLGetString(PREFS_POP3_SERVER, DEFAULT_POP3_SERVER));
addr.Hostname(WorkString);
// mail.f1-software.com
uLong TempPort =
Dexter.XMLGetNumber(PREFS_POP3_PORT, DEFAULT_POP3_PORT);
addr.Service(TempPort);
// POP3 Port Number
// Create the socket
wxSocketClient*
Socket = new wxSocketClient();
Socket->SetTimeout(10); // 10 Second Timeout
// Wait for the Connected event
Socket->Connect(addr,
false);
if(!Socket->WaitOnConnect(-1))
{
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Connection Timed Out");
WriteToErrorTab("<font color=red>Connection To %s [%d] Timed
Out</font>", Dexter.XMLGetString(PREFS_POP3_SERVER,
DEFAULT_POP3_SERVER), Dexter.XMLGetNumber(PREFS_POP3_PORT, DEFAULT_POP3_PORT));
Socket->Close();
return;
}
// Make sure it is really connected
if(!Socket->IsConnected())
{
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Connection Refused?");
WriteToErrorTab("<font color=red>Unable To Connect To %s
[%d]</font>", Dexter.XMLGetString(PREFS_POP3_SERVER,
DEFAULT_POP3_SERVER), Dexter.XMLGetNumber(PREFS_POP3_PORT, DEFAULT_POP3_PORT));
Socket->Close();
return;
}
// At this point, we should have established a connection.
We should wait for the
// +OK to signify that we are ready to process some
commands
ForceRead(Socket);
// This must start with a + sign according to the RFC
if(POP3Message[0] != '+')
{
debugmessage(DEX_DEBUG_LOW,
"** ERROR ** DoPOP3: Server Connected &
Returned Error (Shutdown?) [%s]", POP3Message);
Socket->Close();
return;
}
debugmessage(DEX_DEBUG_LOW,
"Received OK");
// Now we can go ahead and send a USER command to try to
connect to the server
Dexter.StringPrint(WorkString,
"USER %s\r\n",
Dexter.XMLGetString(PREFS_POP3_USERNAME, ""));
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Sending: '%s'",
WorkString);
Socket->Write(WorkString,
Dexter.StringLength(WorkString));
// Wait for the response
ForceRead(Socket);
// See what the server said to us
if(POP3Message[0] != '+')
{
// Some error occured
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Failed Command for USER (%s)",
POP3Message);
Socket->Close();
return;
}
// System is awaiting a password from the user
Dexter.StringPrint(WorkString,
"PASS %s\r\n",
Dexter.XMLGetString(PREFS_POP3_PASSWORD, ""));
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Sending Password '%s'",
WorkString);
Socket->Write(WorkString,
Dexter.StringLength(WorkString));
// Wait for the password response
ForceRead(Socket);
if(POP3Message[0] != '+')
{
// The password check failed
debugmessage(DEX_DEBUG_LOW,
"** ERROR ** DoPOP3: Bad Password [%s]",
POP3Message);
Socket->Close();
return;
}
// Now that we are logged into the POP3 server, send a STAT
command to display info
// About the current mail queue system
Socket->Write("STAT\r\n", 6);
// Wait for the resulting response
ForceRead(Socket);
debugmessage(DEX_DEBUG_LOW,
"DoPop3: STAT Reaponse - '%s'",
POP3Message);
if(POP3Message[0] != '+')
{
debugmessage(DEX_DEBUG_LOW,
"** ERROR ** DoPOP3: Failed To Process STAT
Command (%s)", POP3Message);
}
// The resulting result will contain 3 words (should), +OK,
a mail count and an octet count
Dexter.StringParseResetPointer();
Dexter.StringParseWord(TempWord,
POP3Message, sizeof(TempWord), false, " "); // +OK
Dexter.StringParseFindNextNonSpace(POP3Message);
Dexter.StringParseWord(TempWord,
POP3Message, sizeof(TempWord), false, " "); // Num Messages
Dexter.StringParseFindNextNonSpace(POP3Message);
uLong MessageCount =
Dexter.StringToInteger(TempWord);
Dexter.StringParseWord(TempWord,
POP3Message, sizeof(TempWord), false, " "); // Octet Count
Dexter.StringParseFindNextNonSpace(POP3Message);
uLong ByteCount =
Dexter.StringToInteger(TempWord);
// Display the output of the newly acquired data
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Account Has %d Emails, %d Bytes",
MessageCount, ByteCount);
//Any messages to process?
if(MessageCount == 0)
{
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: No Messages To Process, Sending
QUIT");
Socket->Write("QUIT\r\n", 6); //
Clean Exit
Socket->Close();
return;
}
// Update the Email Tab
Dexter.StringPrint(WorkString,
"POP3 Account Has %d Messages (%.2fKb
Data)", MessageCount, ((float)ByteCount/1024.0f));
uLong EmailsPerTime =
Dexter.XMLGetNumber(PREFS_EMAIL_PER_SESSION, DEFAULT_EMAIL_SESSION);
uLong EmailCheckLoop
= EmailsPerTime;
// Are there more mails on the account than this? Process a
few mails at a time
// Instead of hundreds to help balance load.
if(EmailsPerTime > 0)
{
if(MessageCount > EmailsPerTime)
{
// Some of these messages will be truncated
Dexter.StringPrint(TempWord,
" - Processing First %d Messages Only",
EmailsPerTime);
Dexter.StringAttach(WorkString,
TempWord);
}
} else
{
EmailCheckLoop
= MessageCount; // Get the real message count
instead!
}
// Write the message to the email tab
WriteToEmailTab(WorkString);
// Now we can start a loop to read in each message. Each
message is retreived with RETR
// And will respond with a +OK if it can be grabbed. After
that, the entire message is
// Transmitted. The very last line set will have
"." to symbolize the End of Message.
// For now, we are just dumping the entire message to the
log, and teaching the code how
// To recognize that the end of message has been reached.
There is no DELE command issued
// At this time.
debugmessage(DEX_DEBUG_LOW,
"Checking Email: Attempting To Track %d
Messages", EmailCheckLoop);
for(uLong CheckMessages=0;
CheckMessages<EmailCheckLoop; CheckMessages++)
{
bool ProcessMessage = true;
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: Attempting To Check Message %d",
CheckMessages+1);
// Flush out anything in the Read() buffer completely
//Socket->Discard();
Dexter.StringClear(BufferString); Dexter.StringClear(WorkString); Dexter.StringClear(TempWord);
// We should query for the sixe of the message
Dexter.StringPrint(TempWord,
"LIST %d\r\n", (CheckMessages+1));
Socket->Write(TempWord,
Dexter.StringLength(TempWord));
// Get the response back from the server
ForceRead(Socket);
if(POP3Message[0] != '+')
{
debugmessage(DEX_DEBUG_LOW,
"** ERROR ** DoPOP3[%d]: LIST Command Failed
[%s]", CheckMessages+1, POP3Message);
ProcessMessage
= false;
}
// Scan the received command to get the size of the message
Dexter.StringParseResetPointer();
Dexter.StringClear(TempWord);
Dexter.StringParseWord(TempWord,
POP3Message, 25, false, " "); // +OK
Dexter.StringParseWord(TempWord,
POP3Message, 25, false, " "); // 3
Dexter.StringParseWord(TempWord,
POP3Message, 25, false, " "); // 2125
uLong
SizeInBytes = Dexter.StringToInteger(TempWord);
debugmessage(DEX_DEBUG_LOW,
"DoPOP3[%d]: Size Of Message (Octets) : %d
Bytes", CheckMessages+1, SizeInBytes);
// We could add a size check limit if we wanted to
// Create a buffer size. We should add a good size space
buffer to cover the entire
// Header, so we will use 4Kb for that
uLong
EstimatedBuffer = (4096 + SizeInBytes);
// Try to allocate the memory block
uByte*
FileData = (uByte*)Dexter.AllocMemory(EstimatedBuffer, DEX_MEM_FAST);
if(!FileData)
{
debugmessage(DEX_DEBUG_LOW,
"** ERROR ** DoPOP3[%d]: Couldn't Allocate %d
Bytes of Ram", CheckMessages+1, EstimatedBuffer);
ProcessMessage
= false;
}
else
{
debugmessage(DEX_DEBUG_LOW,
"DoPOP3[%d]: Allocated Block Of Memory: %d
Sizes", CheckMessages+1, EstimatedBuffer);
}
// If the block is allocated, then dump the message into it
if(ProcessMessage == true)
{
// Here we can now issue the RETR command to get the
message
Dexter.StringPrint(TempWord,
"RETR %d\r\n", CheckMessages+1);
Socket->Write(TempWord,
Dexter.StringLength(TempWord));
// We should issue a Pause for the server to issue the
command
//Sleep(100); // 100 ms pause
// Force a Reply
ForceRead(Socket);
if(POP3Message[0] != '+')
{
debugmessage(DEX_DEBUG_LOW,
"** ERROR ** DoPOP3: RETR Command Failed
[%s]", CheckMessages+1, POP3Message);
ProcessMessage
= false;
}
}
if(ProcessMessage == true)
{
// RETR command issued and responded OK, now we can get the
full message
// Dump the entire message to RAM
//Socket->Wait(-1, 100);
Socket->WaitForWrite(1);
Socket->Read(FileData,
EstimatedBuffer);
uLong
LastCount = Socket->LastCount();
debugmessage(DEX_DEBUG_LOW,
"DoPOP3[%d]: Sucked out %d bytes from Socket",
CheckMessages+1, LastCount);
// Free the block
Dexter.FreeMemory(FileData);
}
} // Next CheckMessages
// Shut down the connection
debugmessage(DEX_DEBUG_LOW,
"DoPOP3: All Mail Processed, Issuing
QUIT");
Socket->Write("QUIT\r\n", 6);
Socket->Close();
return;
}
//
----------------------------------------------------------------------------
// ForceRead();
//
// Read a string of data from the socket
in 1Kb chunks. The optional StripCRLF
// (Set to TRUE by default on prototype)
will seek out the CRLF char in the
// Retrieved string and replace it with
a NULL, so it can be handled as a
// Normal string. Intended for
single-line responses only.
//
// If boolean is set to false, there is
no additional processing done to the
// Recovered data.
//
----------------------------------------------------------------------------
void ForceRead(wxSocketClient* sock, const bool StripCRLF)
{
const uLong SIZE_OF_BUFFER = 4096;
char TempString[4096];
TempString[SIZE_OF_BUFFER-1]
= 0;
//Dexter.StringFillCharacter(POP3Message, '\0',
sizeof(POP3Message));
// Grab the data in the current Read buffer
sock->Read(TempString,
SIZE_OF_BUFFER-2); // This is purposely smaller, so
we can always force a NULL at the end of the data
// Ensure this string is always NULL terminated
TempString[SIZE_OF_BUFFER-1]
= 0; // Always NULL the last char in the string
before it's looked at
// This is a dirty way to seek out the \r\n character set,
as StringReplace
// Seems to break. It replaces the first occurence with a
null, so it tries
// To end the string. Without this, some char values would
have strange characters
// At the end and might not even end up being null
terminated.
if(StripCRLF == true)
{
for(uWord DoCheck=0; DoCheck<SIZE_OF_BUFFER;
DoCheck++)
{
if(TempString[DoCheck] == '\r')
{
TempString[DoCheck]
= 0;
DoCheck
= 9999; // Break the loop
}
}
}
// Copy this to the global string entry ready for user
processing
Dexter.StringPrint(POP3Message,
TempString, sizeof(POP3Message));
}
And here is the output of the log:
4.293: DoPOP3: Sending: 'USER *********
'
4.317: DoPOP3: Sending Password 'PASS ******
'
6.566: DoPop3: STAT Response - '+OK 302 3458847'
6.567: DoPOP3: Account Has 302 Emails, 3458847 Bytes
6.594: Checking Email: Attempting To Track 15 Messages
6.594: DoPOP3: Attempting To Check Message 1
6.620: DoPOP3[1]: Size Of Message (Octets) : 3338 Bytes
6.621: DoPOP3[1]: Allocated Block Of Memory: 7434 Sizes
6.685: DoPOP3[1]: Sucked out 3341 bytes from Socket
6.686: DoPOP3: Attempting To Check Message 2
6.711: DoPOP3[2]: Size Of Message (Octets) : 22373 Bytes
6.712: DoPOP3[2]: Allocated Block Of Memory: 26469 Sizes
6.839: DoPOP3[2]: Sucked out 22376 bytes from Socket
6.840: DoPOP3: Attempting To Check Message 3
6.864: DoPOP3[3]: Size Of Message (Octets) : 23055 Bytes
6.865: DoPOP3[3]: Allocated Block Of Memory: 27151 Sizes
6.951: DoPOP3[3]: Sucked out 23058 bytes from Socket
6.952: DoPOP3: Attempting To Check Message 4
6.977: DoPOP3[4]: Size Of Message (Octets) : 3722 Bytes
6.978: DoPOP3[4]: Allocated Block Of Memory: 7818 Sizes
7.017: DoPOP3[4]: Sucked out 3725 bytes from Socket
7.018: DoPOP3: Attempting To Check Message 5
7.044: DoPOP3[5]: Size Of Message (Octets) : 22734 Bytes
7.045: DoPOP3[5]: Allocated Block Of Memory: 26830 Sizes
7.128: DoPOP3[5]: Sucked out 22737 bytes from Socket
7.128: DoPOP3: Attempting To Check Message 6
7.155: DoPOP3[6]: Size Of Message (Octets) : 4952 Bytes
7.156: DoPOP3[6]: Allocated Block Of Memory: 9048 Sizes
7.198: DoPOP3[6]: Sucked out 4955 bytes from Socket
7.199: DoPOP3: Attempting To Check Message 7
7.224: DoPOP3[7]: Size Of Message (Octets) : 3337 Bytes
7.225: DoPOP3[7]: Allocated Block Of Memory: 7433 Sizes
7.264: DoPOP3[7]: Sucked out 3341 bytes from Socket
7.265: DoPOP3: Attempting To Check Message 8
7.290: DoPOP3[8]: Size Of Message (Octets) : 4233 Bytes
7.291: DoPOP3[8]: Allocated Block Of Memory: 8329 Sizes
7.334: DoPOP3[8]: Sucked out 4236 bytes from Socket
7.334: DoPOP3: Attempting To Check Message 9
7.360: DoPOP3[9]: Size Of Message (Octets) : 1411 Bytes
7.361: DoPOP3[9]: Allocated Block Of Memory: 5507 Sizes
7.396: DoPOP3[9]: Sucked out 1414 bytes from Socket
7.397: DoPOP3: Attempting To Check Message 10
7.423: DoPOP3[10]: Size Of Message (Octets) : 19165 Bytes
7.423: DoPOP3[10]: Allocated Block Of Memory: 23261 Sizes
7.493: DoPOP3[10]: Sucked out 17520 bytes from Socket
7.494: DoPOP3: Attempting To Check Message 11
7.495: ** ERROR ** DoPOP3[11]: LIST Command Failed [;]
7.496: DoPOP3[11]: Size Of Message (Octets) : 0 Bytes
7.497: DoPOP3[11]: Allocated Block Of Memory: 4096 Sizes
7.498: DoPOP3: Attempting To Check Message 12
7.519: DoPOP3[12]: Size Of Message (Octets) : 10683 Bytes
7.520: DoPOP3[12]: Allocated Block Of Memory: 14779 Sizes
7.570: DoPOP3[12]: Sucked out 17 bytes from Socket
7.571: DoPOP3: Attempting To Check Message 13
7.581: ** ERROR ** DoPOP3[13]: LIST Command Failed
[Return-path: <35ANISRQKBHkdlldibXiboqp-klobmivdlldib.ZljXkavcy-plcqtXob.Zlj@...>]
7.583: DoPOP3[13]: Size Of Message (Octets) : 0 Bytes
7.584: DoPOP3[13]: Allocated Block Of Memory: 4096 Sizes
7.584: DoPOP3: Attempting To Check Message 14
7.604: DoPOP3[14]: Size Of Message (Octets) : 1389 Bytes
7.605: DoPOP3[14]: Allocated Block Of Memory: 5485 Sizes
7.658: DoPOP3[14]: Sucked out 18 bytes from Socket
7.659: DoPOP3: Attempting To Check Message 15
7.662: ** ERROR ** DoPOP3[15]: LIST Command Failed
[if" alt="" border="0"></a>]
7.663: DoPOP3[15]: Size Of Message (Octets) : 0 Bytes
7.664: DoPOP3[15]: Allocated Block Of Memory: 4096 Sizes
7.665: DoPOP3: All Mail Processed, Issuing QUIT
As you can see, something causes it to freak out on occasions
and im not sure what. It works for the most part, so I could probably use it in
the interim on the mails which do turn out good. Thanks again.
--
Kind Regards,
Andy 'Fish-Guy' Kellett <andy@...>
http://www.f1-software.com
From:
wxMS_developers@yahoogroups.com [mailto:wxMS_developers@yahoogroups.com] On
Behalf Of Dave Silvia
Sent: Saturday, December 20, 2008 10:45 PM
To: wxMS_developers@yahoogroups.com
Subject: {Disarmed} Re: [wxMS_developers] Issues with
POP3/wxSocketClient
Hi, Andy!
It's a little difficult to discuss the problem when the only
information available is that you're using wxSocketClient. The problem may be
further up the line. With only this one piece of information, one must assume
that everything before the call to wxSocketClient methods/functions to retrieve
the messages is performing correctly and that everything that was needed to be
done before the wxSocketClient transactions was done!;)
It's much, much easier to talk about problems and issues if
you attach your project (or a facsimile) to a posting you make from your email
client (Yahoo! Groups does not do attachments!:-< ).
If you're using DialogBlocks, it's even easier to
"share" as all one must needs do is attach the .pjd file
(DialogBlocks project file). This will allow the receiver to build and run on
their own system quite easily.
Any attachments should be in archive format (zip or other)
to reduce size (.pjd's are quite large, but very compressible!;) and to make it
more likely that the receiver's email client/antispam won't prevent its
delivery.
The only thing I can do, from the information available
here, is make a "swag" at a possibility. It appears that an
"undocumented procedure" in wxSocketBase has to be performed first. I
put it in quotes because it actually is documented, but only "before"
the fact. That is, most wxWidgets "Base" classes are not intended to
be used, only derived from. Hence, a developer (like me!;) doesn't often look
at base classes in wxWidgets classes. The assumption being that the derived
wxWidgets class is/has taken care of any parent class necessities.
In looking at the wxSocketBase documentation I see a blurb:
>>>>>
wxSocketBase is the base class for all socket-related
objects, and it defines all basic IO functionality.
Note: (Workaround for implementation limitation for
wxWidgets up to 2.5.x) If you want to use sockets or derived classes such as
wxFTP in a secondary thread, call wxSocketBase::Initialize() (undocumented)
from the main thread before creating any sockets - in wxApp::OnInit for
example.
<<<<<
Now, it does say this is for wxWidgets up to 2.5.x, but it's
the only "swag" I've got right now!:-( If it doesn't help, you might
like to consider archiving an example and attaching it to an email client
generated post.
HTH:
thx,
Dave S.
From a Braille bumper sticker...
If you can read this, you are too close!
wxMS_developers - Development with wxWidgets on MSWindows
http://tech.groups.yahoo.com/group/wxMS_developers/
wxWidgets Code Exchange
http://www.wxCodex.net/
> -- On Sat, 20 Dec 2008
21:20:29 -0500 Andy Kellett wrote --
> Hi,
>
> I'm trying to write a
really simple POP3 client using wxSocketClient which should connect to
> a POP3 account, and
download all messages. It is to be part of my order handling processing
> system and I am having some
odd issues that I can't seem to solve.
>
> I am able to handle
everything up to retrieving the actual message. I have tried a number of
> different methods to try
and get this to work and so far I have not found anything that works
> consistently.
>
> The first method was one I
saw on a wxWidgets forum, involving a large string buffer. Call
> the Read() command and add
the returned string to the main buffer string, parse the newline
> and remove the entire line
to shorten the string, then repeat till the end of the message
> (single line with '.'). This
only works a little bit and the socket seems to stop reading
> after a couple of messages,
mid message, for no apparent reason.
>
> Another idea I had was to
allocate a block of memory big enough to hold the message, and call
> a Read() command with this
buffer sixe, thinking the message would just read into memory
> where I can process it
further. The problem here is that every so often, it doesn't work. It
> works on about 90% of the
messages, but doesn't read in the entire thing, the LIST command
> for the next message still
recovers parts of the previous message. The documentation for
> Read() doesn't state if
there is a limit on the amount of data it transfers at one time, or
> if there is a way to wait
for the buffer to contain a certain amount of data before reading.
>
> I guess my question, is
does someone have any POP3 retreival code anywhere, or could explain
> a process on how to make
this work? I have found samples on the net for everything except
> POP3 hehe =) Any help
is greatly appreciated =) Thanks in advance.
>
> --
> Kind Regards,
>
> Andy 'Fish-Guy' Kellett
<andy@...>