Signing documents located in SharePoint with CoSign - cosign-api

I'm trying to use the CoSign API to get sign fields and sign a docx document located in SharePoint.
I can get the memorystream or byte array from the SharePoint file, using the byte array I've created a FileHandler object but it returns sign fields.
I've posted the helper methods I'm using below, The FileHandle returns an object but the SAPI.SignatureFieldEnumInitEx method returns 0 fields, checking the document with the SharePoint Add-in and the example code returns 2 fields. Problem seem to lie in the byteArray I'm sending in, the item.File.OpenBinary() method to open the document doesn't seem to be correct.
using (SPSite site = new SPSite("http://sharepointweburl"))
{
using (SPWeb web = site.OpenWeb())
{
SPList documents = web.Lists["Documents"];
SPListItem item = documents.GetItemById(8);
Console.WriteLine("Item: {0}", item.Name);
var binaryFile = item.File.OpenBinary();
var handle = DocuSign.GetFileHandleFromStream(binaryFile);
var fields = DocuSign.GetSignatureFieldsFromHandle(handle);
}
}
public static FileHandle GetFileHandleFromStream(byte[] byteArray)
{
FileHandle fileHandle = null;
var sapiByteArray = new SAPIByteArray();
sapiByteArray.FromArray(byteArray);
SAPIContext ctxSigField = new SAPIContextClass();
SAPI.CreateFileHandleByMem(out fileHandle, SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_OFFICE_XML_PACKAGE, 0, sapiByteArray);
return fileHandle;
}
public static DOCXField[] GetSignatureFieldsFromHandle(FileHandle fileHandle)
{
SAPIContext ctxSigField = new SAPIContextClass();
int rc;
int NumOfFields = 0;
rc = SAPI.SignatureFieldEnumInitEx(
hSession,
ctxSigField,
SAPI_ENUM_FILE_TYPE.SAPI_ENUM_FILE_OFFICE_XML_PACKAGE,
"",
fileHandle,
0,
ref NumOfFields
);
DOCXField[] fields = new DOCXField[NumOfFields];
Console.WriteLine("Found {0} signature fields", NumOfFields);
for (int i = 0; i < NumOfFields; i++)
{
fields[i] = new DOCXField();
//Get Signature Field Handle
rc = SAPI.SignatureFieldEnumCont(hSession, ctxSigField, out fields[i].hSigField);
if (rc != 0) throw new Exception("Failed in SignatureFieldEnumCont (" + rc.ToString("X") + ")");
//Get Signature Field Details
rc = SAPI.SignatureFieldInfoGet(
hSession,
fields[i].hSigField,
fields[i].sSettings,
fields[i].sInfo);
if (rc != 0) throw new Exception("Failed in SignatureFieldInfoGet (" + rc.ToString("X") + ")");
}
SAPI.ContextRelease(ctxSigField);
return fields;
}

The CoSign API doesn't support using memory stream for DOCX (only PDF). The only option is to save the memory stream as a temporary file and then call SAPI methods with the file path.

Related

The IsolatedStorageSettings.Save method in Windows Phone: does it save the whole dictionary?

Does the IsolatedStorageSettings.Save method in a Windows Phone application save the whole dictionary regardless of the changes we made in it? I.e. if we have say 50 items in it, and change just one, does the Save method saves (serializes, etc) the whole dictionary again and again? Is there any detailed documentation on this class and does anybody know what data storage format is used "under the hood"?
I've managed to find the implementation of the IsolatedStorageSettings.Save method in the entrails of the Windows Phone emulator VHD images supplied with the Windows Phone SDK (the answer to this question on SO helped me to do that). Here is the source code of the method:
public void Save()
{
lock (this.m_lock)
{
using (IsolatedStorageFileStream isolatedStorageFileStream = this._appStore.OpenFile(this.LocalSettingsPath, 4))
{
using (MemoryStream memoryStream = new MemoryStream())
{
Dictionary<Type, bool> dictionary = new Dictionary<Type, bool>();
StringBuilder stringBuilder = new StringBuilder();
using (Dictionary<string, object>.ValueCollection.Enumerator enumerator = this._settings.get_Values().GetEnumerator())
{
while (enumerator.MoveNext())
{
object current = enumerator.get_Current();
if (current != null)
{
Type type = current.GetType();
if (!type.get_IsPrimitive() && type != typeof(string))
{
dictionary.set_Item(type, true);
if (stringBuilder.get_Length() > 0)
{
stringBuilder.Append('\0');
}
stringBuilder.Append(type.get_AssemblyQualifiedName());
}
}
}
}
stringBuilder.Append(Environment.get_NewLine());
byte[] bytes = Encoding.get_UTF8().GetBytes(stringBuilder.ToString());
memoryStream.Write(bytes, 0, bytes.Length);
DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(Dictionary<string, object>), dictionary.get_Keys());
dataContractSerializer.WriteObject(memoryStream, this._settings);
if (memoryStream.get_Length() > this._appStore.get_AvailableFreeSpace() + isolatedStorageFileStream.get_Length())
{
throw new IsolatedStorageException(Resx.GetString("IsolatedStorageSettings_NotEnoughSpace"));
}
isolatedStorageFileStream.SetLength(0L);
byte[] array = memoryStream.ToArray();
isolatedStorageFileStream.Write(array, 0, array.Length);
}
}
}
}
So, as we can see the whole dictionary is serialized every time when we call Save. And we can see from code what method is used to serialize the collection values.

Error while uploading file method in Client Object Model Sharepoint 2010

Error while uploading file method in Client Object Model + Sharepoint 2010. Once the file got uploaded. After that though the code compiles with no error
I get the error while executing
"{"Value does not fall within the expected range."}
{System.Collections.Generic.SynchronizedReadOnlyCollection}
I have a method which takes care of functionality to upload files
///////////////////////////////////////////////////////////////////////////////////////////
public void Upload_Click(string documentPath, byte[] documentStream)
{
String sharePointSite = "http://cvgwinbasd003:28838/sites/test04";
String documentLibraryUrl = sharePointSite +"/"+ documentPath.Replace('\\','/');
////////////////////////////////////////////////////////////////////
//Get Document List
List documentsList = clientContext.Web.Lists.GetByTitle("Doc1");
var fileCreationInformation = new FileCreationInformation();
//Assign to content byte[] i.e. documentStream
fileCreationInformation.Content = documentStream;
//Allow owerwrite of document
fileCreationInformation.Overwrite = true;
//Upload URL
fileCreationInformation.Url = documentLibraryUrl;
Microsoft.SharePoint.Client.File uploadFile = documentsList.RootFolder.Files.Add(
fileCreationInformation);
//uploadFile.ListItemAllFields.Update();
clientContext.ExecuteQuery();
}
/////////////////////////////////////////////////////////////////////////////////////////////////
In the MVC 3.0 application in the controller I have defined the following method to invoke the upload method.
//////////////////////////////////////////////////////////////////////////////////////////////////
public ActionResult ProcessSubmit(IEnumerable<HttpPostedFileBase> attachments)
{
System.IO.Stream uploadFileStream=null;
byte[] uploadFileBytes;
int fileLength=0;
foreach (HttpPostedFileBase fileUpload in attachments)
{
uploadFileStream = fileUpload.InputStream;
fileLength=fileUpload.ContentLength;
}
uploadFileBytes= new byte[fileLength];
uploadFileStream.Read(uploadFileBytes, 0, fileLength);
using (DocManagementService.DocMgmtClient doc = new DocMgmtClient())
{
doc.Upload_Click("Doc1/Doc2/Doc2.1/", uploadFileBytes);
}
return RedirectToAction("SyncUploadResult");
}
//////////////////////////////////////////////////////////////////////////////////////////////////
Please help me to locate the error
I think your documentLibraryUrl needs to be relative. This is working for me with Sharepoint 2013
[HttpPost]
[ValidateAntiForgeryToken]
[SharePointContextFilter]
public ActionResult Upload()
{
if (Request.Files.Count > 0)
{
HttpPostedFileBase file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
FileCreationInformation newFile = new FileCreationInformation();
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
byte[] array = ms.GetBuffer();
newFile.Content = array;
}
List docs = clientContext.Web.Lists.GetByTitle("Documents");
Folder folder = docs.RootFolder;
clientContext.Load(folder);
clientContext.ExecuteQuery();
newFile.Url = docs.RootFolder.ServerRelativeUrl + "/" + fileName;
Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(newFile);
clientContext.Load(uploadFile);
clientContext.ExecuteQuery();
//Set the metadata
Microsoft.SharePoint.Client.ListItem item = uploadFile.ListItemAllFields;
string docTitle = string.Empty;
item["Title"] = docTitle;
item.Update();
clientContext.ExecuteQuery();
}
}
}
}
return RedirectToAction("Index", new { SPHostUrl = SharePointContext.GetSPHostUrl(HttpContext.Request).AbsoluteUri });
}

how to append one pdf to other pdf file using itextsharp

How to append pages to one pdf file from another pdf file without creating a new pdf using itextsharp. I have metadata attached to one pdf so i just want to add only the other pdf pages,so that first pdf metadata should remain as it is.
Regards
Himvj
Assuming you have 2 pdf files: file1.pdf and file2.pdf that you want to concatenate and save the resulting pdf to file1.pdf (by replacing its contents) you could try the following:
using (var output = new MemoryStream())
{
var document = new Document();
var writer = new PdfCopy(document, output);
document.Open();
foreach (var file in new[] { "file1.pdf", "file2.pdf" })
{
var reader = new PdfReader(file);
int n = reader.NumberOfPages;
PdfImportedPage page;
for (int p = 1; p <= n; p++)
{
page = writer.GetImportedPage(reader, p);
writer.AddPage(page);
}
}
document.Close();
File.WriteAllBytes("file1.pdf", output.ToArray());
}
You can try this it add the whole document with metadata
public static void MergeFiles(string destinationFile, string[] sourceFiles)
{
try
{
//1: Create the MemoryStream for the destination document.
using (MemoryStream ms = new MemoryStream())
{
//2: Create the PdfCopyFields object.
PdfCopyFields copy = new PdfCopyFields(ms);
// - Set the security and other settings for the destination file.
//copy.Writer.SetEncryption(PdfWriter.STRENGTH128BITS, null, "1234", PdfWriter.AllowPrinting | PdfWriter.AllowCopy | PdfWriter.AllowFillIn);
copy.Writer.ViewerPreferences = PdfWriter.PageModeUseOutlines;
// - Create an arraylist to hold bookmarks for later use.
ArrayList outlines = new ArrayList();
int pageOffset = 0;
int f = 0;
//3: Import the documents specified in args[1], args[2], etc...
while (f < sourceFiles.Length)
{
// Grab the file from args[] and open it with PdfReader.
string file = sourceFiles[f];
PdfReader reader = new PdfReader(file);
// Import the pages from the current file.
copy.AddDocument(reader);
// Create an ArrayList of bookmarks in the file being imported.
// ArrayList bookmarkLst = SimpleBookmark.GetBookmark(reader);
// Shift the pages to accomidate any pages that were imported before the current document.
// SimpleBookmark.ShiftPageNumbers(bookmarkLst, pageOffset, null);
// Fill the outlines ArrayList with each bookmark as a HashTable.
// foreach (Hashtable ht in bookmarkLst)
// {
// outlines.Add(ht);
// }
// Set the page offset to the last page imported.
//copy.Writer.SetPageSize(rec);
pageOffset += reader.NumberOfPages;
f++;
}
//4: Put the outlines from all documents under a new "Root" outline and
// set them for destination document
// copy.Writer.Outlines = GetBookmarks("Root", ((Hashtable)outlines[0])["Page"], outlines);
//5: Close the PdfCopyFields object.
copy.Close();
//6: Save the MemoryStream to a file.
MemoryStreamToFile(ms, destinationFile);
}
}
catch (System.Exception e)
{
System.Console.Error.WriteLine(e.Message);
System.Console.Error.WriteLine(e.StackTrace);
System.Console.ReadLine();
}
}
public static void MemoryStreamToFile(MemoryStream MS, string FileName)
{
using (FileStream fs = new FileStream(#FileName, FileMode.Create))
{
byte[] data = MS.ToArray();
fs.Write(data, 0, data.Length);
fs.Close();
}
}

How to read .mp3 files in wcf?

How to read the .mp3 audio files ?
I wrote the following code.
public static byte[] ReadFully(Stream stream)
{
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
It accepts .3gp,.caf foramat streams .why it's not taking .mp3 files?
}
I used the below code to download a mp3 file from my REST WCF Service:
[WebGet]
public Stream GetMp3()
{
byte[] buffer;
WebOperationContext.Current.OutgoingResponse.ContentType = "audio/mp3";
using (FileStream ms = new FileStream(#"C:\Sample.mp3", FileMode.Open))
{
int length = (int)ms.Length;
WebOperationContext.Current.OutgoingResponse.ContentLength = length;
buffer = new byte[length];
int sum = 0;
int count;
while ((count = ms.Read(buffer, sum, length - sum)) > 0)
{
sum += count;
}
ms.Close();
}
return new MemoryStream(buffer);
}
UPDATE: Upload an mp3 file to Restful WCF service
Server side method:
[WebInvoke]
public string RecieveMp3(Stream mp3Stream)
{
byte[] buffer = new byte[5000000];
using (FileStream ms = new FileStream("C:\\Temp\\Test1.mp3", FileMode.OpenOrCreate))
{
int read = mp3Stream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
}
return "Recieved Mp3 file";
}
NOTE:
1. Make sure that you have permissions on the folder to write the mp3 file for the user associated with the app pool under which the wcf service is running
2. For testing purpose i have hard coded the byte array size to be a large value.
Client to call the service:
private string UseRestSharpApproachForFiles(string serviceBaseUrl, string resourceUrl, Method method, string filepath)
{
var client = new RestClient();
client.BaseUrl = serviceBaseUrl;
var request = new RestRequest(method) { DateFormat = DataFormat.Xml.ToString(), Resource = resourceUrl };
request.AddFile("stream", filepath);
var response = client.Execute(request);
string responseString;
if (response.StatusCode == HttpStatusCode.OK)
{
responseString = HttpUtility.HtmlDecode(response.Content);
}
else
{
responseString = response.StatusDescription + " --------------------" + HttpUtility.HtmlDecode(response.Content);
}
return responseString;
}
Am using the 3rd party dll for invoking the rest service called RestSharp.

Programmatically upload XSN to SharePoint

I have a bunch of InfoPath form templates (xsn) which I want to upload to a SharePoint list programmatically. My program has to upload these form templates to different lists based on predefined logic. When I upload the browser-enabled form templates (xsn) with my code, the forms do not work:
/// <summary>
/// Uploads a file to the specified sharepoint list
/// </summary>
/// <param name="listName"></param>
/// <param name="fileInfo"></param>
/// <param name="listVersion"></param>
/// <returns></returns>
public static bool UploadFile(string listName, FileInfo fileInfo, string listVersion)
{
WebRequest request = WebRequest.Create(fileInfo.URL);
request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
request.Method = "PUT";
byte[] buffer = new byte[1024];
using (Stream stream = request.GetRequestStream())
{
using (MemoryStream ms = new MemoryStream(fileInfo.Bytes))
{
for (int i = ms.Read(buffer, 0, buffer.Length); i > 0; i = ms.Read(buffer, 0, buffer.Length))
stream.Write(buffer, 0, i);
}
}
WebResponse response = request.GetResponse();
response.Close();
var client = new Lists.ListsSoapClient();
var batch = new XElement("Batch",
new XAttribute("OnError", "Continue"),
new XAttribute("ListVersion", listVersion),
new XAttribute("PreCalc", "TRUE"));
var method = new XElement("Method",
new XAttribute("ID", "1"),
new XAttribute("Cmd", "Update"),
new XElement("Field",
new XAttribute("Name", "ID")),
new XElement("Field",
new XAttribute("Name", "FileRef"),
fileInfo.URL));
foreach (string key in fileInfo.Properties.Keys)
{
object value = fileInfo.Properties[key];
method.Add(new XElement("Field",
new XAttribute("Name", key),
fileInfo.Properties[key]));
}
batch.Add(method);
var element = client.UpdateListItems(listName, batch);
var code = element.Elements().First().Elements().First().Value;
if (code != "0x00000000")
throw new Exception(code);
return true;
}
It seems there is more to be done that just pushing a file stream into the list.
Anyone have an idea how to do this?
EDIT More specifically, the error message I get is: This form template is not enabled for viewing in the browser.
UPDATE When I publish the same form with Microsoft InfoPath it works.
you can use this code to convert your uploaded form in browser enabled form as:
FormsService localFormsService;
SPFarm localFarm = SPFarm.Local;
SPSite localSite = new SPSite("http://ServerName");
SPWeb localWeb = localSite.AllWebs["SiteName"];
try
{
localFormsService = localFarm.Services.GetValue<FormsService>(FormsService.ServiceName);
SPFile localFile = localWeb.GetFile("FormLibrary/Forms/FormTemplate.xsn");
localFormsService.BrowserEnableUserFormTemplate(localFile);
Console.Write("Press Enter to Continue");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
Console.Write("Press Enter to Continue");
Console.ReadLine();
}
or you can use this link for more details as:
http://msdn.microsoft.com/en-us/library/microsoft.office.infopath.server.administration.formsservice.browserenableuserformtemplate.aspx