if (contentType.contains("multipart")) {
// content may contain attachments
Multipart multiPart = (Multipart) message.getContent();
numberOfParts = multiPart.getCount();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
BodyPart part = multiPart.getBodyPart(partCount);
String disposition = part.getDisposition();
InputStream inputStream = null;
if (disposition == null)
{
MimeBodyPart mbp = (MimeBodyPart) multiPart.getBodyPart(partCount);
if (mbp.getContent() instanceof MimeMultipart){
MimeMultipart mmp = (MimeMultipart) mbp.getContent();
messageContent = mmp.getBodyPart(0).getContent().toString();
//System.out.println("bodyContent " + bodyContent);
}
else
{
messageContent = multiPart.getBodyPart(partCount).getContent().toString();
}
}
else if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
// this part is attachment
String fileName = part.getFileName();
attachFiles += fileName + ", ";
//part.saveFile(saveDirectory + File.separator + fileName);
}else if (Part.INLINE.equalsIgnoreCase(part.getDisposition())) {
// this part is attachment
String fileName = part.getFileName();
attachFiles += fileName + ", ";
// mbp.saveFile(saveDirectory + File.separator + fileName);
}
else {
// this part may be the message content
messageContent = part.getContent().toString();
}
}
if (attachFiles.length() > 1) {
attachFiles = attachFiles.substring(0, attachFiles.length() - 2);
}
} else if (contentType.contains("text/plain") || contentType.contains("text/html")) {
Object content = message.getContent();
if (content != null) {messageContent = content.toString(); }
}
And now this type of message text / plain, text / html gets well. The problem is the email multipart / related when the message has attachments and content is HTML, then gets some news and some not. I noticed that it is dependent on this line:
messageContent = mmp.getBodyPart (0). getContent (). toString ();
If instead of "0" is "partCount" gets all but one particular, if instead of "0" is "1" gets me this one specific and does not charge others. numberOfParts this one particular message is "3" and the other "2". I have no idea what is wrong, maybe wrong parameters are passed?
I'm not really sure what problem you're trying to solve, but just in case this JavaMail FAQ entry might be helpful.
multipart/mixed and multipart/related are very similar in that they have one main part and a bunch of other parts usually thought of as "attachments". Sometimes the disposition will tell you that it's an attachment, and sometimes it won't. Some mailers aren't very consistent in their use of disposition.
One of the unusual cases is multipart/alternative, but it doesn't sound like that's the problem you're running in to.
Related
I am trying to connect to a mailbox and read the messages and attachments. Here when there is any mail with a digital signature, only the smime.7ps file is read and others(xml,pdf etc.,) are ignored. I could observe that in such mails only the signature part of mail is read and body part is ignored. I am using Multipart here. Please let me know if there is any different way of handling which could help me to get the body part attachments read for mails with Digital Signature? Here is the part of my code which fetches the messages/attachments:
if (contentType.contains("multipart")){
Multipart multiPart = (Multipart) message.getContent();
int numberOfParts = multiPart.getCount();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(partCount);
if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
// this part is attachment
String fileName = part.getFileName();
attachFiles += fileName + ", ";
part.saveFile(SaveDirectory + File.separator + fileName);
} else {
// this part may be the message content
messageContent = part.getContent().toString();
}
}
if (attachFiles.length() > 1) {
attachFiles = attachFiles.substring(0, attachFiles.length() - 2);
}
//}
} else if (contentType.contains("text/plain") || contentType.contains("text/html")) {
Object content = message.getContent();
if (content != null) {
messageContent = content.toString();
}
}
Thanks Shannon! Your input of nested multiparts actually helped me to solve the issue!
MimeMultipart multiPart = (MimeMultipart) message.getContent(); //* Reading the Email Message & its contents*
//***Your code for Different actions with Email Message
int numberOfParts = multiPart.getCount();
for (int partCount = 0; partCount < numberOfParts; partCount++) {
//***Reading Body Part contents from the Email Message
MimeBodyPart part = (MimeBodyPart) multiPart.getBodyPart(partCount);
//***Your Code for Different actions with Body part contents
//***Now the below step would help you to check if the above retrieved content(part) is having any further multiparts nested in it.
//***Once the check is true, then you can instantiate that content again as a multipart and retrieve the related details.
if(part.getContent() instanceof Multipart){
Multipart multipart = (Multipart) part.getContent();
for (int j = 0; j < multipart.getCount(); j++) {
MimeBodyPart bodyPart = (MimeBodyPart)multipart.getBodyPart(j);
}
}
}
I find the best way to save game data in Unity3D Game engine.
At first, I serialize objects using BinaryFormatter.
But I heard this way has some issues and is not suitable for save.
So, What is the best or recommended way for saving game state?
In my case, save format must be byte array.
But I heard this way has some issues and not suitable for save.
That's right. On some devices, there are issues with BinaryFormatter. It gets worse when you update or change the class. Your old settings might be lost since the classes non longer match. Sometimes, you get an exception when reading the saved data due to this.
Also, on iOS, you have to add Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes"); or you will have problems with BinaryFormatter.
The best way to save is with PlayerPrefs and Json. You can learn how to do that here.
In my case, save format must be byte array
In this case, you can convert it to json then convert the json string to byte array. You can then use File.WriteAllBytes and File.ReadAllBytes to save and read the byte array.
Here is a Generic class that can be used to save data. Almost the-same as this but it does not use PlayerPrefs. It uses file to save the json data.
DataSaver class:
public class DataSaver
{
//Save Data
public static void saveData<T>(T dataToSave, string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Convert To Json then to bytes
string jsonData = JsonUtility.ToJson(dataToSave, true);
byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
}
//Debug.Log(path);
try
{
File.WriteAllBytes(tempPath, jsonByte);
Debug.Log("Saved Data to: " + tempPath.Replace("/", "\\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To PlayerInfo Data to: " + tempPath.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
}
}
//Load Data
public static T loadData<T>(string dataFileName)
{
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return default(T);
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return default(T);
}
//Load saved Json
byte[] jsonByte = null;
try
{
jsonByte = File.ReadAllBytes(tempPath);
Debug.Log("Loaded Data from: " + tempPath.Replace("/", "\\"));
}
catch (Exception e)
{
Debug.LogWarning("Failed To Load Data from: " + tempPath.Replace("/", "\\"));
Debug.LogWarning("Error: " + e.Message);
}
//Convert to json string
string jsonData = Encoding.ASCII.GetString(jsonByte);
//Convert to Object
object resultValue = JsonUtility.FromJson<T>(jsonData);
return (T)Convert.ChangeType(resultValue, typeof(T));
}
public static bool deleteData(string dataFileName)
{
bool success = false;
//Load Data
string tempPath = Path.Combine(Application.persistentDataPath, "data");
tempPath = Path.Combine(tempPath, dataFileName + ".txt");
//Exit if Directory or File does not exist
if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
{
Debug.LogWarning("Directory does not exist");
return false;
}
if (!File.Exists(tempPath))
{
Debug.Log("File does not exist");
return false;
}
try
{
File.Delete(tempPath);
Debug.Log("Data deleted from: " + tempPath.Replace("/", "\\"));
success = true;
}
catch (Exception e)
{
Debug.LogWarning("Failed To Delete Data: " + e.Message);
}
return success;
}
}
USAGE:
Example class to Save:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Save Data:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
//Save data from PlayerInfo to a file named players
DataSaver.saveData(saveData, "players");
Load Data:
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
if (loadedData == null)
{
return;
}
//Display loaded Data
Debug.Log("Life: " + loadedData.life);
Debug.Log("High Score: " + loadedData.highScore);
for (int i = 0; i < loadedData.ID.Count; i++)
{
Debug.Log("ID: " + loadedData.ID[i]);
}
for (int i = 0; i < loadedData.Amounts.Count; i++)
{
Debug.Log("Amounts: " + loadedData.Amounts[i]);
}
Delete Data:
DataSaver.deleteData("players");
I know this post is old, but in case other users also find it while searching for save strategies, remember:
PlayerPrefs is not for storing game state. It is explicitly named "PlayerPrefs" to indicate its use: storing player preferences. It is essentially plain text. It can easily be located, opened, and edited by any player. This may not be a concern for all developers, but it will matter to many whose games are competitive.
Use PlayerPrefs for Options menu settings like volume sliders and graphics settings: things where you don't care that the player can set and change them at will.
Use I/O and serialization for saving game data, or send it to a server as Json. These methods are more secure than PlayerPrefs, even if you encrypt the data before saving.
I have studied the Files, Storage and Networking instructions on the Codename One website. I am trying to
save files selected by the Codename One filechooser to the device (simulator, Android, iPhone)
retrieve the files saved locally in whatever device they got saved on.
Here is the code I used:
final Button getFileChooser = new Button("Get file chooser");
getFileChooser.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if (FileChooser.isAvailable()) {
FileChooser.showOpenDialog(".pdf, .jpg, .jpeg, .png", e2-> {
String file = (String)e2.getSource();
if (file == null) {
hi.add("No file was selected");
hi.revalidate();
} else {
String extension = null;
if (file.lastIndexOf(".") > 0) {
extension = file.substring(file.lastIndexOf(".")+1);
ToastBar.showMessage("1: " + file, FontImage.MATERIAL_CHECK);
rawFilename.setText("raw: " + file);
//java.util.List<String> filepathParsed = StringUtil.tokenize(file, "[/.]");
StringBuilder hi = new StringBuilder(file);
if (file.startsWith("file://"))
hi.delete(0, 7);
int lastIndexPeriod = hi.toString().lastIndexOf(".");
Log.p(hi.toString());
String ext = hi.toString().substring(lastIndexPeriod);
String hmore = hi.toString().substring(0, lastIndexPeriod -1);
String hi2 = hmore +/* "/file" +*/ ext;/*hi;*/
Log.p("hi2 = " + hi2);
secondFilename.setText("2nd: " + hi2);
//secondFilename.setText((String)evt.getSource());
try {
saveFileToDevice(file, ext);
} catch (URISyntaxException e) {
e.getMessage();
}
//sendFileViaEmail(hi2, file);
} else {
ToastBar.showMessage("2: " + file + " " + extension, FontImage.MATERIAL_CHECK);
}
}
hi.revalidate();
});
}
}
});
protected void saveFileToDevice(String hi, String ext) throws URISyntaxException{
URI uri = new URI(hi);
String path = uri.getPath();
Log.p("uri path: " + uri.getPath() + " ; scheme: " + uri.getScheme());
/*if (path.contains("..jpg")) {
int indexLastPeriodBeforeExt = path.lastIndexOf(".");
path = path.substring(0, indexLastPeriodBeforeExt) + path.substring(indexLastPeriodBeforeExt+ 1);
Log.p("new path: " + path);
}*/
if (Display.getInstance().getPlatformName().equals("and"))
path = "file://" +path;
String home = FileSystemStorage.getInstance().getAppHomePath();
char sep = FileSystemStorage.getInstance().getFileSystemSeparator();
String userDir = home + sep + "myapp";
/*if (hi.startsWith("file://")) {
hi = hi.substring(7);
}*/
int index = hi.lastIndexOf("/");
hi = hi.substring(index + 1);
Log.p("hi after substring 7: " + hi);
FileSystemStorage.getInstance().mkdir(userDir);
String fPath = userDir + sep + hi ;
/* if (hi.contains("..jpg")) {
int indexLastPeriodBeforeExt = hi.lastIndexOf(".");
hi = hi.substring(0, indexLastPeriodBeforeExt) + hi.substring(indexLastPeriodBeforeExt+ 1);
Log.p("new hi: " + hi);
}*/
Log.p("does it exist? " + FileSystemStorage.getInstance().exists(userDir));
String imageFile = userDir + sep + hi;
String[] roots = FileSystemStorage.getInstance().getRoots();
if (roots.length > 0) {
for (int i = 0; i < roots.length; i++)
Log.p("roots" + i + " " + roots[i]);
}
try {
String[] files = FileSystemStorage.getInstance().listFiles(userDir);
for (int i = 0; i < files.length; i++) {
Log.p(i + " " + files[i]);
//secondName = files[files.length-1];
Log.p("secondname: " + secondName);
}
sendFileViaEmail(imageFile, ".jpg");
} catch (IOException e) {
e.getMessage();
}
}
protected void sendFileViaEmail(String hi2, String file) {
Message m = new Message("Test message");
//m.getAttachments().put(file, "image/jpeg");
m.setAttachment(hi2);
m.setAttachmentMimeType(Message.MIME_IMAGE_JPG);
//m.setMimeType(Message.MIME_IMAGE_JPG);
//m.getAttachments().put(imageAttachmentUri, "image/png");
Display.getInstance().sendMessage(new String[] {"myemail#example.com"}, "test message cn1", m);
}
I added the getFileChooser button to my Form after importing the cn1-filechooser library to my project and refreshed libs. The filechooser works -- I tried it on the simulator, Android device and iPhone.
My issue is here:
String file retrieves what looks like a URI. I tried to convert the URI to a File and when I run the following code to see that the files are stored I see them in my logs, although in a funny order, which I'm ok with.
String[] files = FileSystemStorage.getInstance().listFiles(userDir);
for (int i = 0; i < files.length; i++) {
Log.p(i + " " + files[i]);
//secondName = files[files.length-1];
Log.p("secondname: " + secondName);
}
How do retrieve a valid, uncorrupted version of this file from FileSystemStorage? Am I storing it wrong? Whenever I run the method to send the file via email, it opens Outlook (on my Desktop) but no files is attached? (I assume that the file is invalid/corrupted when trying to retrieve it from FileSytemStorage -- please help.) I hardcoded .jpg as MIME-type but only as a test; my goal is to be able to save/restore .pdf, .png, .jpg, and.jpeg files.
Thanks!
**EDIT: ** This seems to show that the file was actually saved to my app's storage. How do I stream the content of the file be copied/uploaded or emailed from my app?
Mobile phones don't allow that. They don't have a file system like desktops have. So file chooser really launches a tool to help you pick a file from a different app, this file is then copied to your local app sandbox where you can get access to the content of the app.
Naturally this won't work for save as it would mean you could potentially corrupt a file within another application so you are restricted from writing to the directories of other applications installed or even knowing which applications are installed and where...
To transfer a file to a different app you have the share intent which you can use via the share button or the low level API's in display. This allows you to send an image to whatsapp or similar functionality that makes sense in a mobile phone.
I am trying to read a text file in my air project. It is actually the config file used by TinkerProxy. I have the following so far:
//Read settings from TinkerProxy Config File
var TextFileLoader:URLLoader = new URLLoader();
var ArrayOfLines:Array;
TextFileLoader.addEventListener(Event.COMPLETE, onLoaded);
TextFileLoader.load(new URLRequest("/tinkerproxy-2_0/serproxy.cfg"));
//TextFileLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
function onLoaded(e:Event):void {
ArrayOfLines = e.target.data.split(/\r/);
trace(e.target.data);
}
trace(ArrayOfLines[0]);
What I'm really trying to do is find the 'net_port1=5331' entry and store '5331' in a variable.
Here is a sample of the text file:
# Generated by TinkerProxy Configurator
#
# Timeout in seconds
# 0 means infinite, no timeout
timeout=0
newlines_to_nils=false
comm_ports=1
serial_device1=COM1
net_port1=5331
comm_baud1=9600
comm_databits1=8
comm_stopbits1=1
comm_parity1=none
The file is autogenerated so I can not edit it (or rather I'd want to read it as it is generated.)
I'm able to see the data via trace(e.target.data) but I cannot access the data via trace(ArrayOfLines[0]); for instance.
What am I missing?
Thanks in advance.
You probably need to split on \n (Unix) or \r\n (Windows), not \r.
Usually when loading a text file from the filesystem and breaking into lines, I normalize line endings by doing this:
var lines:Array = text.replace(/\r\n/g, "\n").split("\n");
Then you can iterate over the lines and decode each line as desired. The file appears to be akin to .properties format, for which there is no built in parser in AS3 (like XML, JSON, or URLVariables) but it's a pretty simple format. For example, this:
var props:Object = {};
for each(var line:String in lines){
// skip blank lines and comment lines
if(line == "" || line.charAt(0) == "#")
continue;
var arr:Array = line.split("=");
if(arr.length == 2)
props[arr[0]] = arr[1];
}
trace(JSON.stringify(props, null, 2))
Outputs this:
{
"comm_parity1": "none",
"comm_ports": "1 ",
"newlines_to_nils": "false",
"comm_baud1": "9600",
"serial_device1": "COM1",
"comm_databits1": "8",
"timeout": "0",
"comm_stopbits1": "1",
"net_port1": "5331"
}
Which allows you to access properties by name:
trace(props.net_port1); // "5331"
(Note that all values are strings, so for example newlines_to_nils is not false, it is "false".)
Alternatively, you could search for the key you are looking for and extract just the data you want:
var key:String = "net_port1=";
var index:int = text.indexOf(key);
if(index != -1){
// extract text after the desired search key
var value:String = text.substring(index + key.length);
// parseInt will read until it hits a non-numeric character
var net_port1:int = parseInt(value);
trace(net_port1); // 5331
}
Here is the solution that worked for me. Thanks again to Aaron for his answer on properties. I may use that in the future.
//Read settings from TinkerProxy Config File
var TextFileLoader:URLLoader = new URLLoader();
var ArrayOfLines:Array;
var Port:int;
var COM:int;
TextFileLoader.addEventListener(Event.COMPLETE, onLoaded);
TextFileLoader.load(new URLRequest("/tinkerproxy-2_0/serproxy.cfg"));
function findSubstring(array:Array, string:String):int {
for(var i:int = 0; i < array.length; i++){
if(array[i].indexOf(string) > -1){
return i; //Index of Substring
}
}
return -1; //Not Found
}
function onLoaded(e:Event):void {
ArrayOfLines = e.target.data.split(String.fromCharCode(13));
if(findSubstring(ArrayOfLines, "net_port") > -1){
Port = Number(ArrayOfLines[findSubstring(ArrayOfLines, "net_port")].split("=")[1]);
}
else{
Port = 5331; //Default if not port is found.
}
if(findSubstring(ArrayOfLines, "serial_device1") > -1){
COM = Number(ArrayOfLines[findSubstring(ArrayOfLines, "serial_device1")].split("serial_device1=COM")[1]);
}
else{
COM = 1; //Default if not port is found.
}
trace("COM: " + COM + " Port: " + Port);
}
I am parsing big text files and it's working fine for some time but after few minutes it give me exception (An unhandled exception of type 'System.UnauthorizedAccessException' occurred in System.Core.dll
Additional information: Access to the path is denied.)
I get exception on below mention line.
accessor = MemoryMapped.CreateViewAccessor(offset, length, MemoryMappedFileAccess.Read);
Below is my function
public static void CityStateZipAndZip4(string FilePath,long offset,long length,string spName)
{
try
{
long indexBreak = offset;
string fileName = Path.GetFileName(FilePath);
if (fileName.Contains(".txt"))
fileName = fileName.Replace(".txt", "");
System.IO.FileStream file = new System.IO.FileStream(#FilePath, FileMode.Open,FileAccess.Read, FileShare.Read );
Int64 b = file.Length;
MemoryMappedFile MemoryMapped = MemoryMappedFile.CreateFromFile(file, fileName, b, MemoryMappedFileAccess.Read, null, HandleInheritability.Inheritable, false);
using (MemoryMapped)
{
//long offset = 182; // 256 megabytes
//long length = 364; // 512 megabytes
MemoryMappedViewAccessor accessor = MemoryMapped.CreateViewAccessor(offset, length, MemoryMappedFileAccess.Read);
byte byteValue;
int index = 0;
int count = 0;
StringBuilder message = new StringBuilder();
do
{
if (indexBreak == index)
{
count = count + 1;
accessor.Dispose();
string NewRecord = message.ToString();
offset = offset + indexBreak;
length = length + indexBreak;
if (NewRecord.IndexOf("'") != -1)
{ NewRecord = NewRecord.Replace("'", "''"); }
// string Sql = "insert into " + DBTableName + " (ID, DataString) values( " + count + ",'" + NewRecord + "')";
string Code = "";
if (spName == AppConfig.sp_CityStateZip)
{
Code = NewRecord.Trim().Substring(0, 1);
}
InsertUpdateAndDeleteDB(spName, NewRecord.Trim (), Code);
accessor = MemoryMapped.CreateViewAccessor(offset, length, MemoryMappedFileAccess.Read);
message = new StringBuilder();
index = 0;
//break;
}
byteValue = accessor.ReadByte(index);
if (byteValue != 0)
{
char asciiChar = (char)byteValue;
message.Append(asciiChar);
}
index++;
} while (byteValue != 0);
}
MemoryMapped.Dispose();
}
catch (FileNotFoundException)
{
Console.WriteLine("Memory-mapped file does not exist. Run Process A first.");
}
}
Somewhere deep in resource processing code we have something like this:
try {
// Try loading some strings here.
} catch {
// Oops, could not load strings, try another way.
}
Exception is thrown and handled already, it would never show up in your application. The only way to see it is to attach debugger and observe this message.
As you could see from the code, it has nothing to do with your problem. The real problem here is what debugger shows you something you should not see.
Run the solution without debugging mode and it works fine.
This exception means that your program does not get Read access to the file from Windows.
Have you made sure that this file is not locked when your program tries to read it ?
For example, it could be a file that your own program is currently using.
If not, try to run your program as an Administrator and see if it makes a difference.