Send Mail/Task/Appointment with Redemption - outlook

I am trying to programmatically send a Mail/Task/Appointment to a user and I have the problem, that every time I send them the first one will get stuck in my outbox... It seems that the first one sent to Outlook has no/looses its sent-date and will stay forever in my outbox.
Here is the code for example "sending a task notification"
using (MapiSession session = new MapiSession())
{
var item = session.CreateItem(Outlook.OlItemType.olTaskItem) as RDOTaskItem;
[..]
try
{
item.Subject = "SUBJECT";
item.Body = "BODY;
item.StartDate = DateTime.Now;
item.DueDate = DateTime.Now;
item.Recipients.Add("test#mail.com");
item.Recipients.Add("test2#mail.com");
item.Recipients.ResolveAll();
item.Assign();
item.Save();
item.Send();
}
[..]
}
Thanks in advance.

So I am not really shure what is the problem so far...
If all receivers are other persons then myself this should work...
Here is my code for sendig a TaskItem
private void NotifyByTask(OutlookNotificationTypes notificationType)
{
Application app = new Application();
var item = app.CreateItem(OlItemType.olTaskItem) as TaskItem;
try
{
item.Subject = this.Subject;
item.Body = this.Body;
if (this.Start != DateTime.MinValue)
{
item.StartDate = this.Start;
item.ReminderSet = true;
item.ReminderPlaySound = true;
item.ReminderTime = this.Start.AddMinutes(-5);
}
if (this.End != DateTime.MinValue)
{
item.DueDate = this.End;
}
item.PercentComplete = this.PercentComplete;
StringBuilder categories = new StringBuilder();
foreach (String category in this.Categories)
{
categories.Append(category);
}
item.Categories = categories.ToString();
bool sendingToMyself = false;
if (this.NotificationType == OutlookNotificationTypes.TaskRequest)
{
// this will add all recipients and checks if Receiver is yourself
sendingToMyself = item.AddRecipients(this.Recipients, OlMailRecipientType.olTo);
}
if (this.NotificationType == OutlookNotificationTypes.TaskRequest
&& (!sendingToMyself))
{
item.Recipients.ResolveAll();
item.Assign();
item.Save();
item.Send();
}
else
{
item.Save();
//insert element
if (this.ItemSaved != null)
{
Microsoft.Office.Interop.Outlook.MAPIFolder folder =
item.Parent as Microsoft.Office.Interop.Outlook.MAPIFolder;
if (folder != null)
{
try
{
String storeId = folder.StoreID;
String entryId = item.EntryID;
this.ItemSaved(storeId, entryId);
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(folder);
}
}
}
}
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
}
}

Related

Action.Picker returns invalid/wrong Uri (How to get path or byte[] from multiple picked gallery img)

I have an forms app where i need to pick "1 to many" images from the phone storage.
For this i use the dependency injection system.
My problem is the somewhere i get an Android.netUri that resolves to a file that do not exist... and to a file name that i have never seen before.
The kicker is that if i pick pictures that was takes within the last couple of hours this code works...
Im am at the end of my hoap, i really hope someone can point me to something that i'm doing wrong.
i start the Picker activity with:
[assembly: Dependency(typeof(ImagePickerService))]
namespace MyApp.Droid
{
public class ImagePickerService : Java.Lang.Object, IImagePickerService
{
public async Task OpenGallery()
{
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (status != PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Storage))
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Need Storage permission to access to your photos.", ToastLength.Long).Show();
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Storage });
status = results[Permission.Storage];
}
if (status == PermissionStatus.Granted)
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Pick max 20 images", ToastLength.Long).Show();
var imageIntent = new Intent(Intent.ActionPick);
imageIntent.SetType("image/*");
imageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
imageIntent.SetAction(Intent.ActionPick);
CrossCurrentActivity.Current.Activity.StartActivityForResult(Intent.CreateChooser(imageIntent, "Pick pictures"), 100);
}
else if (status != PermissionStatus.Unknown)
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Permission Denied. Can not continue, try again.", ToastLength.Long).Show();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Error. Can not continue, try again.", ToastLength.Long).Show();
}
}
}
then in my MainActivity.cs i have the OnActivityResult
I have tried to use the ContentResolver.OpenInputStream to get the image bytes with no luck, so this is commented out atm.
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == OPENGALLERYCODE && resultCode == Result.Ok)
{
List<string> images = new List<string>();
if (data != null)
{
ClipData clipData = data.ClipData;
if (clipData != null)
{
for (int i = 0; i < clipData.ItemCount; i++)
{
ClipData.Item item = clipData.GetItemAt(i);
/*
var stream = ContentResolver.OpenInputStream(item.Uri); //This throws "FileNotFound"
byte[] byteArray;
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
byteArray = memoryStream.ToArray();
stream.Close();
stream = null;
}
stream = ContentResolver.OpenInputStream(item.Uri);
var exif = new ExifInterface(stream);
stream.Close();
*/
Android.Net.Uri uri = item.Uri;
var path = GetActualPathFromFile(uri);
if (path != null)
{
var tmpImgPath = RotateToOriginalDimention(path);
images.Add(tmpImgPath);
}
}
}
else
{
Android.Net.Uri uri = data.Data;
var path = GetActualPathFromFile(uri);
if (path != null)
{
var tmpImgPath = RotateToOriginalDimention(path);
images.Add(tmpImgPath);
}
}
MessagingCenter.Send<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", images);
}
}
}
And the GetActualPathFromFile (also in my MainActivity.cs)
The hole func is below but i hit this part of the code and get at "FileNotFound"
(...)
else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
var retval2 = getDataColumn(this, uri, null, null);
if (File.Exists(retval2)) //<----------------------- This returns "false"
{
return retval2;
}
else
{
throw new Exception("file not found " + retval2);
}
}
(...)
The Hole GetActualPathFromFile
private string GetActualPathFromFile(Android.Net.Uri uri)
{
bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;
if (isKitKat && DocumentsContract.IsDocumentUri(this, uri))
{
// ExternalStorageProvider
if (isExternalStorageDocument(uri))
{
string docId = DocumentsContract.GetDocumentId(uri);
char[] chars = { ':' };
string[] split = docId.Split(chars);
string type = split[0];
if ("primary".Equals(type, StringComparison.OrdinalIgnoreCase))
{
var retval = Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri))
{
string id = DocumentsContract.GetDocumentId(uri);
Android.Net.Uri contentUri = ContentUris.WithAppendedId(
Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(id));
//System.Diagnostics.Debug.WriteLine(contentUri.ToString());
var retval = getDataColumn(this, contentUri, null, null);
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
// MediaProvider
else if (isMediaDocument(uri))
{
String docId = DocumentsContract.GetDocumentId(uri);
char[] chars = { ':' };
String[] split = docId.Split(chars);
String type = split[0];
Android.Net.Uri contentUri = null;
if ("image".Equals(type))
{
contentUri = MediaStore.Images.Media.ExternalContentUri;
}
else if ("video".Equals(type))
{
contentUri = MediaStore.Video.Media.ExternalContentUri;
}
else if ("audio".Equals(type))
{
contentUri = MediaStore.Audio.Media.ExternalContentUri;
}
String selection = "_id=?";
String[] selectionArgs = new String[]
{
split[1]
};
var retval = getDataColumn(this, contentUri, selection, selectionArgs);
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
}
// MediaStore (and general)
else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
// Return the remote address
if (isGooglePhotosUri(uri))
{
var retval = uri.LastPathSegment;
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
var retval2 = getDataColumn(this, uri, null, null);
if (File.Exists(retval2))
{
return retval2;
}
else
{
throw new Exception("file not found " + retval2);
}
}
// File
else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
var retval = uri.Path;
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
throw new Exception("file not found ");
}
public static String getDataColumn(Context context, Android.Net.Uri uri, String selection, String[] selectionArgs)
{
ICursor cursor = null;
String column = "_data";
String[] projection =
{
column
};
try
{
cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.MoveToFirst())
{
int index = cursor.GetColumnIndexOrThrow(column);
return cursor.GetString(index);
}
}
finally
{
if (cursor != null)
cursor.Close();
}
return null;
}
//Whether the Uri authority is ExternalStorageProvider.
public static bool isExternalStorageDocument(Android.Net.Uri uri)
{
return "com.android.externalstorage.documents".Equals(uri.Authority);
}
//Whether the Uri authority is DownloadsProvider.
public static bool isDownloadsDocument(Android.Net.Uri uri)
{
return "com.android.providers.downloads.documents".Equals(uri.Authority);
}
//Whether the Uri authority is MediaProvider.
public static bool isMediaDocument(Android.Net.Uri uri)
{
return "com.android.providers.media.documents".Equals(uri.Authority);
}
//Whether the Uri authority is Google Photos.
public static bool isGooglePhotosUri(Android.Net.Uri uri)
{
return "com.google.android.apps.photos.content".Equals(uri.Authority);
}
Found out that the real problem was that Google Photos App was not updating and was still showing images that were deleted.
After 2x reboot of the phone, Google Photos app finally updated.
So this looks more like a cache problem with Google Foto than a xamarin problem.

Save files in asp.net folder with reference in the database from a desktop client

ASP.NET WEB API: Hi, I would like to know to save files in asp.net web api folder with the link reference in database from desktop client. I searched it online and got some implementation still it's not workin.
Below are what I got so far. I hope someone can help me out with that.
Your contribution will really help.
My api controller code
[HttpPost]
public HttpResponseMessage PostFile()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
if (postedFile != null)
{
var filePath = HttpContext.Current.Server.MapPath("~/files" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
My client side code
OpenFileDialog fd = new OpenFileDialog();
private void btnUpload_Click(object sender, EventArgs e)
{
bool uploadStatus = false;
fd.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp;)|*.jpg; *jpeg; *.gif; *.bmp;";
fd.Title = "Choose image";
if (fd.ShowDialog() == DialogResult.OK)
{
picUpload.Image = new Bitmap(fd.FileName);
foreach(String localfile in fd.FileNames)
{
var url = "url";
var filepath = #"\";
Random ran = new Random();
var uploadFileName = "img" + ran.Next(999).ToString();
uploadStatus = UploadConfig(url, filepath, localfile, uploadFileName);
}
}
if (uploadStatus)
{
MessageBox.Show("Successful");
}
else
{
MessageBox.Show("Failed");
}
}
bool UploadConfig(string url, string filePath, string localFileName, string UploadFileName)
{
bool isFileUploaded = false;
try
{
using (HttpClient client = new HttpClient())
{
var fs = File.Open(localFileName, FileMode.Open);
var fi = new FileInfo(localFileName);
UploadDetails uploadDetails = null;
bool fileUpload = false;
MultipartFormDataContent content = new MultipartFormDataContent();
content.Headers.Add("filePath",filePath);
content.Add(new StreamContent(fs), "\"files\"",
string.Format("\"{0}\"", UploadFileName + fi.Extension));
Task taskUpload = client.PostAsync(url, content).ContinueWith(task =>
{
if(task.Status == TaskStatus.RanToCompletion)
{
var res = task.Result;
if (res.IsSuccessStatusCode)
{
uploadDetails = res.Content.ReadAsAsync<UploadDetails>().Result;
if (uploadDetails != null)
{
fileUpload = true;
}
}
}
fs.Dispose();
});
taskUpload.Wait();
if (fileUpload)
{
isFileUploaded = true;
client.Dispose();
}
}
}
catch (Exception e)
{
isFileUploaded = false;
}
return isFileUploaded;
}

Outlook Error MAPI_E_OBJECT_CHANGED at Save() RDOEmail

Calling Save() twice raice MAPI_E_OBJECT_CHANGED error. The weird thing is if I select another mail on the grid and go back and then select the first one again and perform the action it works fine. This only happens with imap accounts.
Code:
public void UpdateMailObject(bool linked)
{
Outlook._Application outlookApplication = null;
Redemption.RDOMail rdoEmail = null;
Redemption.RDOSession rdoSession = null;
RDOFolder folder = null;
RDOStores stores = null;
RDOStore store = null;
RDOStore unwStore = null;
Outlook.Explorer outlookExplorer = null;
Outlook.MailItem selectedMail = null;
try
{
outlookApplication = new Outlook.Application();
rdoSession = new Redemption.RDOSession();
object MAPIOBJECT = outlookApplication.Session.GetType().InvokeMember("MAPIOBJECT", BindingFlags.GetProperty, null,
outlookApplication.Session, null);
rdoSession.MAPIOBJECT = MAPIOBJECT;
outlookExplorer = outlookApplication.ActiveExplorer();
selectedMail = outlookExplorer.Selection.OfType<Outlook.MailItem>().FirstOrDefault();
RDOMail rdoMailAux = rdoSession.GetRDOObjectFromOutlookObject(selectedMail, true) as RDOMail;
folder = rdoMailAux.Parent as RDOFolder;
Marshal.ReleaseComObject(rdoMailAux);
string storeId = folder.StoreID;
stores = rdoSession.Stores;
store = stores.GetStoreFromID(storeId);
unwStore = stores.UnwrapStore(store);
rdoEmail = unwStore.GetMessageFromID(selectedMail.EntryID, null);
string sGUID = PS_PUBLIC_STRINGS.ToString("B");
int iID = rdoEmail.GetIDsFromNames(sGUID, GMLINK);
if (iID != 0)
{
rdoEmail.set_Fields(iID, linked);
}
rdoEmail.Save();
}
finally
{
if (outlookApplication != null)
{
Marshal.ReleaseComObject(outlookApplication);
}
if (folder != null)
{
Marshal.ReleaseComObject(folder);
}
if (stores != null)
{
Marshal.ReleaseComObject(stores);
}
if (store != null)
{
Marshal.ReleaseComObject(store);
}
if (unwStore != null)
{
Marshal.ReleaseComObject(unwStore);
}
if (rdoEmail != null)
{
Marshal.ReleaseComObject(rdoEmail);
}
if (outlookExplorer != null)
{
Marshal.ReleaseComObject(outlookExplorer);
}
if (rdoSession != null)
{
Marshal.ReleaseComObject(rdoSession);
}
}
}

Zeroconf.ResolveAsync was freezed

I tried to use Zeroconf to get all the devices. When i called the ResolveAsync, the code got freezed.
I am running Xamarin Form on Android phone. It didn't produce any error or force close. It just stays there.
public async Task Update()
{
DeviceInfoStruct device;
string service = Constant.LAUNCHER_THRIFT_SERVICE + "local.";
int tried = 0;
List<DeviceInfoStruct> toDelete = new List<DeviceInfoStruct>();
foreach (var d in _devices)
{
toDelete.Add(d);
}
try
{
if (IsHotSpotIp())
{
device = LauncherClient.GetDeviceInfo(Constant.HOTSPOT_DEVICE_IP);
if (device != null)
{
device.Ip = Constant.HOTSPOT_DEVICE_IP;
if (!_devices.Any(d => d.Ip == device.Ip))
{
_devices.Add(device);
}
}
}
do
{
for (int i = 0; i < 5; i++)
{
foreach (var r in await ZeroconfResolver.ResolveAsync(service))
{
if (r.Services.ContainsKey(service))
{
device = LauncherClient.GetDeviceInfo(r.IPAddress);
if (device != null)
{
device.Ip = r.IPAddress;
if (!_devices.Any(d => d.Ip == device.Ip))
{
Debug.WriteLine("Found Device " + device.DeviceName + " # " + device.Ip);
_devices.Add(device);
toDelete.RemoveAll(d => d.Ip == device.Ip);
}
}
}
}
}
tried++;
} while ((tried < 2) && (_devices.Count == 0));
foreach (var d in toDelete)
{
if (LauncherClient.GetDeviceInfo(d.Ip) == null)
{
_devices.Remove(d);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Locks from GitHub
buttonHosting.Command = new Command( () =>
{
#if __ANDROID__
var wifi = (Android.Net.Wifi.WifiManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.WifiService);
var mlock = wifi.CreateMulticastLock("Zeroconf lock");
try
{
mlock.Acquire();
var deviceModel = new DevicesViewModel();
var devices = deviceModel.GetAvailableDevicesAsync().Result;
foreach (var device in devices)
{
System.Diagnostics.Debug.WriteLine("Device Info: Name = " + device.DeviceName);
System.Diagnostics.Debug.WriteLine(" Version = " + device.DeviceVersion);
}
}
finally
{
mlock.Release();
}
#endif
//await Navigation.PushAsync(new MeetingPage(), true);
});
The code below will just print a list of devices
ILookup<string, string> domains = await ZeroconfResolver.BrowseDomainsAsync();
var responses = await ZeroconfResolver.ResolveAsync(domains.Select(g => g.Key));
foreach (var resp in responses)
Console.WriteLine(resp);
I can only see other devices' but not the one I wanted to look at...

ActionFilter to read Contents before RedirectToAction

I wish to record deletes and edits, and thought the best way would be to apply An actionFilter
Attribute to my delete and edit [ post ] methods
But because the end results is a redirect to action, my Context.Result is always null
because there is only a Context.RedirectToAction results available.
Now before i go creating some code to plug into my delete and Edit functions, has anyone tried something like this!, and could you possibly advise?
Thanks
Action Code:
[HttpPost, ValidateInput(false)]
[SiteChangeLogger(LogType = "Update", TableName = "Affiliates")]
public ActionResult Edit(Affiliate affiliate, FormCollection form)
{
var existing = db2.Affiliates.SingleOrDefault(x => x.AffiliateId == affiliate.AffiliateId);
ViewBag.before = Common.Strings.Base64Encode(Common.Strings.ToJsonString(existing));
if (ModelState.IsValid)
{
try
{
var curFiles = new NameValueCollection();
curFiles["AffiliateLogo"] = affiliate.AffiliateLogo;
if (!String.IsNullOrWhiteSpace(form["AffiliateLogo"]))
{
UploadFiles(form,curFiles);
TryUpdateModel(affiliate, form);
var oldFileName = affiliate.AffiliateLogo;
var newFileName = Common.Strings.RandomFileName();
new WebImage(Server.MapPath("~/Content/images/" + affiliate.AffiliateLogo))
.Resize(200, 50, true, true)
.Crop(1, 1)
.Save(Server.MapPath("~/Content/images/" + newFileName), "png", true);
affiliate.AffiliateLogo = newFileName + ".png";
Common.Common.TryAndDeleteFile("~/Content/images/" + oldFileName);
}
else
{
affiliate.AffiliateLogo = existing.AffiliateLogo;
}
}
catch (Exception ex)
{
Common.Common.CompileErrorMessage(ex,"ADMIN.Affiliate.Edit");
}
finally
{
db.Entry(affiliate).State = EntityState.Modified;
db.SaveChanges();
}
ViewBag.after = Common.Strings.Base64Encode(Common.Strings.ToJsonString(affiliate));
return RedirectToAction("Index");
}
return View(affiliate);
}
my Filter Code
public override void OnResultExecuted(ResultExecutedContext fc)
{
var viewResult = fc.Result as ViewResult;
if(viewResult == null) return;
var beforeData = viewResult.ViewBag.before;
var afterData = viewResult.ViewBag.after;
if (beforeData == null && afterData == null) return;
var ctx = new SgeGamesContext();
var eventId = 0;
var siteChangeLogEvent = ctx.SiteChangeLogEvents.SingleOrDefault(x => x.SiteChangeLogEventName == LogType);
if (siteChangeLogEvent != null)
{
eventId = siteChangeLogEvent.SiteChangeLogEventId;
}
var model = new Sge.Games.Data.Models.SiteChangeLog
{
SiteChangeLogTable = TableName,
SiteId = 1,
SiteChangeLogAfterContent = afterData,
SiteChangeLogBeforeContent = beforeData,
SiteChangeLogEventId = eventId
};
ctx.SiteChangeLogs.Add(model);
ctx.SaveChanges();
base.OnResultExecuted(fc);
}
You could access the ViewBag directly, you don't need a ViewResult:
public override void OnResultExecuted(ResultExecutedContext fc)
{
var before = fc.Controller.ViewBag.before;
var after = fc.Controller.ViewBag.after;
...
}
Also you probably want to use the OnActionExecuted event instead of OnResultExecuted.

Resources