Cannot delete an email message using POP3 - c#

I have code that uses POP3 to access an email account and search for messages that were sent but the address did not exist. After processing them, I delete the failure message. I have one client who can get and process the messages, but is not able to delete them. They keep getting the message Error deleting message 1: -ERR The specified message is out of range.
The code for my delete method is below. This works for most clients, and is pretty simple, so I'm not sure why it isn't working.
public bool Delete(int index)
{
bool result = false;
String response = SendReceive("DELE ", index.ToString());
if (response.StartsWith("+OK"))
result = true;
else
logger.Log("Error deleting message " + index + ": " + response, Verbose.LogImportant);
return result;
}
For the SendReceive method:
private String SendReceive(String command, String parameter)
{
String result = null;
try
{
String myCommand = command.ToUpper().Trim() + " " + parameter.Trim() + Environment.NewLine;
byte[] data = System.Text.Encoding.ASCII.GetBytes(myCommand.ToCharArray());
tcpClient.GetStream().Write(data, 0, data.Length);
result = streamReader.ReadLine();
}
catch { } // Not logged in...
return result;
}
The index is taken directly from the received email, and the connection is not closed until after the delete method has processed. Since there has to be an email returned to run this method, and since the index runs from 1 to n, with a 1 being sent, I don't see what is causing this to fail.

The SendReceive() call looks wrong. My guess is that it should probably have a {0} in the format string. In other words, your code is probably sending DELE instead of DELE 1.

Related

StreamReader doesn't retrieve everything from NetworkStream (TCP and C#)

I'm working on a project, where you have to retrieve data from a server and display it in the UI. It's a newsgroups server, that contains about 250 groups in total.
The output from the server SHOULD as far as I understand, be stored in a NetworkStream object and is read from a StreamReader which saves each line into a string.
This works, but unfortunately it seems like it doesn't finish reading everything before finishing the method call.
Next time I call another command and read it from the StreamReader it then returns the rest of the output from the previous command.
I've been struggling with this for hours now, and can't see how to fix this.
This is my code:
public ObservableCollection<Newsgroup> GetNewsGroups()
{
ObservableCollection<Newsgroup> newsgroups = new ObservableCollection<Newsgroup>();
if(connectionStatus.Equals(ConnectionStatus.CONNECTED) && loginStatus.Equals(LoginStatus.LOGGED_IN))
{
byte[] sendMessage = Encoding.UTF8.GetBytes("LIST\n");
// Write to the server
ns.Write(sendMessage, 0, sendMessage.Length);
Console.WriteLine("Sent {0} bytes to server...", sendMessage.Length);
ns.Flush();
// b) Read from the server
reader = new StreamReader(ns, Encoding.UTF8);
// We want to ignore the first line, as it just contains information about the data
string test = reader.ReadLine();
Console.WriteLine(test);
string recieveMessage = "";
if (ns.CanRead)
{
while (reader.Peek() >= 0)
{
recieveMessage = reader.ReadLine();
Console.WriteLine("Got this message {0} back from the server", recieveMessage);
// This part will simply remove the annoying numbers after the newsgroup name
int firstSpaceIndex = recieveMessage.IndexOf(" ");
string refactoredGroupName = recieveMessage.Substring(0, firstSpaceIndex);
newsgroups.Add(new Newsgroup { GroupName = refactoredGroupName });
}
}
}
return newsgroups;
}
I'd be interested to see what information about the data you are throwing away on the first line (what's in "test" variable). If it tells you how many bytes are coming your way, you should use that information to retrieve the correct amount of data instead of Peek.
If the last line contains a single period, change your while loop to look like this instead:
recieveMessage = reader.ReadLine();
while (recieveMessage != ".")
{
Console.WriteLine("Got this message {0} back from the server", recieveMessage); // This part will simply remove the annoying numbers after the newsgroup name int
firstSpaceIndex = recieveMessage.IndexOf(" ");
string refactoredGroupName = recieveMessage.Substring(0, firstSpaceIndex);
newsgroups.Add(new Newsgroup { GroupName = refactoredGroupName });
recieveMessage = reader.ReadLine();
}

How to take mvc c# server errors +number to line number

Hi I've coded my MVC c# application and it's all fine, however there does seem to be a few bugs. This being one of my first applications, I'm not surprised.
The application though is internal and so I do get good feedback from the users.
They do give me the screens shots 'Server Error in ........ Application'
This gives me the controller action which does help narrow down the error.
However how do I turn the +number at end of the line to an actual line number.
I'm aware that this is some sort of byte offset, but getting a rough idea of the line number would be helpful. Is there a plugin or something I can use?
Or is there another way to handle these. I've got a Base controller that all the controllers extend from - I've seen some things that say you can use this to write to a file to give you information about the error. If I made it a generic file (similar to the php error file) then that would help me with any application I make.
You can handle server errors in Global.asax inside Application_Error() method. Create a well designed error page and save it somewhere inside your project. In global asax create a method and put error handling code inside it. See below for example code.
protected void Application_Error()
{
if (httpContext.AllErrors != null)
{
// you can handle message
var message = HttpUtility.HtmlEncode(httpContext.AllErrors[0]);
//you can redirect ugly server error page to the one you created
httpContext.Response.Redirect($"~/Error/Global");
}
}
Just developing on what hhh's answer here.
This is what I've got at the end.
protected void Application_Error()
{
if (this.Context.AllErrors != null)
{
var p = Path.Combine(Server.MapPath("~"), "Errors.log");
var message = DateTime.Now.ToString();
message = message + " " + this.Context.User.Identity.Name;
message = message + " " + this.Context.Request.Url;
message = message + Environment.NewLine;
message = message + "Post";
message = message + Environment.NewLine;
string[] keys = this.Context.Request.Form.AllKeys;
for (int i = 0; i < keys.Length; i++)
{
message = message+keys[i] + ":" + this.Context.Request.Form[keys[i]];
message = message + Environment.NewLine;
}
message = message + Environment.NewLine;
// you can handle message
message = message+ HttpUtility.HtmlEncode(this.Context.AllErrors[0]);
message = message + Environment.NewLine;
message = message + "----------------------------------";
message = message + Environment.NewLine;
System.IO.File.AppendAllText(p, message);
//you can redirect ugly server error page to the one you created
}
}
Basically giving you a file with all the key variables in the there.
Feel free to modify as you wish.

Sending multi part sms with GSM using AT Commands

I have a windows application for sending SMS connecting to a GSM Modem. I only use AT Commands for connecting to port and sending text.
My problem is I can't send a message more that one part (each part is 160 characters for English and 70 characters for Farsi).
Here is the part I command the port to send sms using AT commands:
ExecCommand(port, "AT", 300, "No phone connected at " + strPortName + ".");
ExecCommand(port, "AT+CMGF=1", 300, "Failed to set message format.");
var command = "AT+CSCS=\"" + "HEX" + "\"";
ExecCommand(port, command, 300, "Failed to support unicode");
ExecCommand(port, "AT+CSMP=1,167,0,8", 300, "Failed to set message properties.");
command = "AT+CMGS=\"" + phoneNo + "\"";
ExecCommand(port, command, 300, "Failed to accept phoneNo");
message = message.ToCharArray().Select(Convert.ToInt32).Select(value => String.Format("{0:X}", value)).Aggregate("", (current, hexOutput) => current + hexOutput.PadLeft(4, '0'));
command = message + char.ConvertFromUtf32(26) + "\r";
var recievedData = ExecCommand(port, command, 3000, "Failed to send message");
And here is ExecCommand method
public string ExecCommand(SerialPort port, string command, int responseTimeout, string errorMessage)
{
try
{
// receiveNow = new AutoResetEvent();
port.DiscardOutBuffer();
port.DiscardInBuffer();
receiveNow.Reset();
port.Write(command + "\r");
//Thread.Sleep(3000); //3 seconds
string input = ReadResponse(port, responseTimeout);
if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
throw new ApplicationException("No success message was received.");
return input;
}
catch (Exception ex)
{
throw new ApplicationException(errorMessage, ex);
}
}
General AT command handling
You are on the right track, I am pleased to see several basic things done right (terminating AT command lines with \r, waiting for "\r\n> " for AT+CMGS, and waiting for the OK final result code instead of sleeping), very good start!
You do need however to change the structure somewhat. First you need to handle all the other final result codes and not just OK. And you should treat the AT+CMGS command differently from the other commands since you should wait for two things (first the prefix and later the final result code after sending the message text) for that command compared to waiting only for one thing (e.g. the final result code) for those. Also all responses from the modem are complete lines (except the "\r\n> " prefix), so change your algorithm to process the response(s) line by line.
String input;
do {
input = ReadLine(port, responseTimeout);
} while (!isFinalResultCode(input));
None of the commands you are using in the question produces an intermediate response for consumption, but if you were to run a command like AT+CPBR you would consume those intermediate responses inside that loop (and you would have to move the final result test into the loop before attempting to consume the line as an intermediate response).
You can see the is_final_result function in atinout or corresponding functions in ST-Ericsson's U300 RIL (see link and notes in this answer).
Multipart SMS
I think this is not possible in text mode. See the link suggested by Naser Asadi for details on multipart SMS in PDU mode. Also some useful information at
http://mobiletidings.com/2009/02/18/combining-sms-messages/ and http://developer.nokia.com/community/discussion/showthread.php/109602-Concatenated-SMS-in-PDU-Mode.

Socket receives the correct bytes, bytes translate to empty string

I've been breaking my head over a bug in this system I've been building. Basically, I use sockets to communicate between two C# applications. Or rather a Unity C# script server and a C# client application.
With manual tests, the system works perfectly fine, no anomalies whatsoever.
In order to test performance and multi-user functionality, I wrote up a tester class which launches multiple threads(clients), and have those fire X amount of messages at the server. Here's where my problem occurs...Sometimes.
When a Socket sends or receives, it returns an integer container the amount of bytes that was sent/received. When the problem occurs, I can see that the correct amount of bytes arrived at the server. However, after putting the bytes into a string, suddenly I'm left with an empty string, instead of the message I'd normally see here.
I'm at a loss at to what's causing this problem. I'm using Encoding.Default.GetString() to translate the bytes into a string.
Any help is appreciated!
David
public void ReceiveFromClient (Socket handlerSocket)
{
serverBuffer = new byte[iBufferSize]; //iBufferSize = 8192;
int i = handlerSocket.Receive (serverBuffer);
Debug.Log ("Bytes received: " + i);
string message = Encoding.UTF8.GetString (serverBuffer, 0, i);
Debug.Log ("Message received: " + message);
//Do stuff with the message
}
bool SendMessageToUnity(string input)
{//returns a bool saying whether the message was sent or not
if (clientSocket != null)
{
if (clientSocket.Connected)
{
byte[] bytes = Encoding.UTF8.GetBytes(input+"|");
txtOutput.BeginInvoke(new Action(() => txtOutput.AppendText("Sending message: " + Encoding.UTF8.GetString(bytes) + Environment.NewLine)));
int i = clientSocket.Send(bytes);
txtOutput.BeginInvoke(new Action(() => txtOutput.AppendText("Sending "+i+" bytes. "+ Environment.NewLine)));
return true;
}
}
return false;
}
Look for for a zero value ('\0') in your array of bytes before converting it to a string.
private string GetString(byte[] data)
{
data = data.Where(b => b != 0).ToArray();
return Encoding.UTF8.GetString(data);
}
If you get the byte array correctly than the problem in the Encoding.
Check the sending Encoding usually UTF8 but you have to check it out.
and then var inputStr = Encoding.UTF8.GetString(InputByteArray);
^^

Outlook MailItem Save/SaveAs

I have an outlook add-in that allows the user to save an email into a database. When the user does save the email I modify the email subject so it can be identified as being saved.
Saving the email can happen in two ways. Via a button on the tool bar which allows the user to save any email they want, and also via a prompt which appears when a new email is put into the Sent Items folder. Both methods use the same form to save the email!
OK, now to the problem ....
In the process of saving the email I use the mailItem.SaveAs method to put it into the file store. After this has completed successfully i want to change the subject of the email which still exists in outlook to say that it has been saved successfully. I do this by changing myItem.Subject and then using the mailItem.Save method to save the change.
The above works perfectly when the email isn't being saved via the prompt method. So when the user tries to save the email after they send it the mailItem.Save method does not work.
I have narrowed it down to it actually working if i put the myItem.Save() line before the myItem.SaveAs() line, but obviously if I do this I can not guarantee the email was actually saved properly.
So does any one know of a reason that the mailItem.Save method would want to not work after the mailItem.SaveAs method as been called?
Thank you in advance to any suggestions to what might be the problem.
EDIT : Code
if (_item is Outlook.MailItem) { // if the incoming item is an Outlook mail Item
// cast as a mail item
Outlook.MailItem myItem = (Outlook.MailItem)_item;
if (directoryExists(directoryTemp)) { // if the temporary directory exists
bool _profiled = true;
// copy the item as type .msg in the temporary location
myItem.SaveAs(saveTemp, Outlook.OlSaveAsType.olMSG);
// setup impersonation to copy the file to a secure location
PImpersonateUser _iU = new PImpersonateUser();
// do impersonation
try {
_iU.Impersonate("******", "******", "******");
if (File.Exists(savefile)) { // if file already exists in the location
// delete existing file
File.Delete(savefile);
}
// move the temporary file to the secure location with the proper name
File.Move(saveTemp, savefile);
string year = "";
if (ipt_year.SelectedItem != null) { // else if year has been selected
year = ipt_year.SelectedItem.ToString();
}
_profile.profileEmail(folderString(_subject_), _fileName, year);
} catch (Exception e) {
_profiled = false;
// if impersonation fails cancel the impersonation
_iU.Undo();
// show error
MessageBox.Show(e.Source + "\n\n" + e.Message + "\n\n" + e.StackTrace, "SaveAs() Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
} finally {
_iU.Undo();
}
if (_profiled) { // if the email was profiled successfully
// mark the original email as being profiled
markAsProfiled();
}
} else {
// if temporary file save fails throw error
MessageBox.Show("Temporary Directory (" + directoryTemp + ") Does Not Exist!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
and the markAsProfiled function ...
private void markAsProfiled() {
if (_item is Outlook.MailItem) { // if the incoming item is an Outlook mail Item
// cast as a mail item
Outlook.MailItem myItem = (Outlook.MailItem)_item;
// make sure subject doesnt already have a profiled flag in the subject
_subject_ = _subject_.Replace("[PROFILED] - ", "");
// add a profiled flag in the subject of the email
myItem.Subject = "[PROFILED] - " + _subject_;
// add a yellow flag to the email
myItem.FlagIcon = Microsoft.Office.Interop.Outlook.OlFlagIcon.olYellowFlagIcon;
// save email with changes made
myItem.Save();
//MessageBox.Show("Mark as Profiled :: " + myItem.Subject + " :: " + myItem.Saved.ToString() + " :: ");
}
}
if this is still relevant to you: You could use a self-defined column in which you could write wether the saving was successfull or not.
Example code:
mail.UserProperties.Add("Profiled", Outlook.OlUserPropertyType.olText, true);
mail.UserProperties["Profiled"].Value = "Yes";
mail.Save();
The only disadvantage is that you've to add the field to the displayed columns in Outlook. (maybe that can be done programmatically)
About why your method doesn't work: I could imagine that Outlook doesn't like it when you change the subject of an email after it was sent.

Categories

Resources