C# — Load a TreeView from JSON, Save a TreeView to JSON

Here are a few snippets of code I needed for internal tools…

TreeView –> JSON

private void recurseTree(TreeNode treeNode, Chilkat.JsonObject json)
    {
    string tag;
    if (treeNode.Tag == null)
        {
        tag = treeNode.Name;
        }
    else
        {
        tag = treeNode.Tag.ToString();
        if (tag.Length == 0)
            {
            tag = treeNode.Name;
            }
        }

    int numChildren = treeNode.Nodes.Count;
    if (numChildren == 0)
        {
        json.AppendString(tag, treeNode.Text);
        return;
        }

    Chilkat.JsonObject jObj = json.AppendObject(tag);

    foreach (TreeNode tn in treeNode.Nodes)
        {
        recurseTree(tn,jObj);
        }
    }

private void btnTreeViewToJson_Click(object sender, EventArgs e)
    {
    // Convert treeview1 to JSON.
    Chilkat.JsonObject json = new Chilkat.JsonObject();

    TreeNodeCollection nodes = treeView1.Nodes;
    foreach (TreeNode n in nodes)
        {
        recurseTree(n,json);
        }

    json.EmitCompact = false;
    textBox1.Text = json.Emit();
    }

JSON –> TreeView

void buildTreeView(TreeNode node, Chilkat.JsonObject json)
    {
    int i;
    int n = json.Size;
    for (i = 0; i < n; i++)
        {
        if (json.TypeAt(i) == 3)
            {
            TreeNode tn = new TreeNode();
            
            tn.Tag = json.NameAt(i);
            tn.Name = json.NameAt(i);
            tn.Text = json.NameAt(i);
            node.Nodes.Add(tn);

            Chilkat.JsonObject jObj = json.ObjectAt(i);
            buildTreeView(tn, jObj);
            }
        else
            {
            // This is a string.
            TreeNode tn = new TreeNode();
            tn.Tag = json.NameAt(i);
            tn.Name = json.NameAt(i);
            tn.Text = json.StringAt(i);
            node.Nodes.Add(tn);
            }
        }
    }

private void loadTreeView()
    {
    treeView1.BeginUpdate();

    Chilkat.JsonObject json = new Chilkat.JsonObject();

    json.LoadFile("c:/ck2000/appData/builder/treeView.json");

    // recursively add the JSON nodes to the treeview.
    TreeNode tn = new TreeNode();
    tn.Tag = json.NameAt(0);
    tn.Name = json.NameAt(0);
    tn.Text = json.NameAt(0);
    treeView1.Nodes.Add(tn);

    Chilkat.JsonObject jObj = json.ObjectAt(0);
    buildTreeView(tn, jObj);

    treeView1.EndUpdate();
    }

treeView1.Nodes.Clear();
loadTreeView();
...

C++ Zip Example to Append In-Memory Binary and String Data


void qa_create_zip_from_data(void)
{
CkZip zip;

zip.NewZip("qa_output/test.zip");

// This is the content of the files to be added to the .zip
const char *fileContents = "The quick brown fox jumped over the lazy dog. The quick brown fox jumped over the lazy dog. The quick brown fox jumped over the lazy dog.";

// AppendString2 returns a CkZipEntry, so make sure to get it and delete it if not needed..
// If NULL is returned, then the AppendString2 failed.
CkZipEntry *ent = zip.AppendString2("quickBrownFox1.txt",fileContents,"ansi");
if (ent) { delete ent; ent = 0; }

// Another way of adding in-memory data to a .zip is by calling AppendData. This is good for binary (non-text) data.
// In this case, we'll use the bytes of fileContents.
size_t szContent = strlen(fileContents);

CkByteData binaryContent;
// It is possible to let the CkByteData "borrow" data.  This avoid copying the bytes, which is good if the amount
// of data is large.
binaryContent.borrowData(fileContents,szContent);

// Add the binaryContent to the zip.
ent = zip.AppendData("quickBrownFox2.txt",binaryContent);
if (ent) { delete ent; ent = 0; }

// We now have a zip object (not yet a file on disk) that contains 2 entries: quickBrownFox1.txt and quickBrownFox2.txt
// Write the .zip to a file  (this is where the actual compression occurs)
// This writes the .zip to "qa_output/test.zip"
bool success = zip.WriteZipAndClose();
if (!success)
    {
    printf("%s\n",zip.lastErrorText());
    }
else
    {
    printf("success.\n");
    }
}

C Language Callbacks

This example demonstrates the general pattern for implementing some standard event callbacks functions for the Chilkat “C” API.  All Chilkat “classes” what have events will use the standard Chilkat events shown in the example below (AbortCheck, PercentDone, and ProgressInfo).

This example demonstrates callbacks for an SFTP download, but the same technique applies to any other Chilkat “class”, such as HTTP, FTP2, MailMan, Rest, etc.

#include <stdio.h>

#include <C_CkSFtp.h>

BOOL myAbortCheck()
    {
    // To abort the current Chilkat method call, return non-zero.
    return 0;
    }

BOOL myPercentDone(int pctDone)
    {
    printf("Percent Done: %d\n",pctDone);

    // To abort the current Chilkat method call, return non-zero.
    return 0;
    }

void myProgressInfo(const char *name, const char *value)
    {
    printf("%s: %s\n",name,value);
    }

void ChilkatSample(void)
    {
    HCkSFtp sftp;
    BOOL success;
    int port;
    const char *hostname;
    const char *handle;

    // Declare event callbacks.
    BOOL (*fnAbortCheck)() = myAbortCheck;
    BOOL (*fnPercentDone)(int pctDone) = myPercentDone;
    void (*fnProgressInfo)(const char *name, const char *value) = myProgressInfo;

    sftp = CkSFtp_Create();

    //  Any string automatically begins a fully-functional 30-day trial.
    success = CkSFtp_UnlockComponent(sftp,"Anything for 30-day trial");
    if (success != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    // Setup event callbacks.
    CkSFtp_setAbortCheck(sftp, fnAbortCheck);
    CkSFtp_setPercentDone(sftp, fnPercentDone);
    CkSFtp_setProgressInfo(sftp, fnProgressInfo);

    // Make sure to set a HeartbeatMs for AbortCheck / PercentDone callbacks..
    // Set the HeartbeatMs to 250 milliseconds.
    CkSFtp_putHeartbeatMs(sftp,250);

    //  Set some timeouts, in milliseconds:
    CkSFtp_putConnectTimeoutMs(sftp,5000);
    CkSFtp_putIdleTimeoutMs(sftp,10000);

    //  Connect to the SSH server.
    //  The standard SSH port = 22
    //  The hostname may be a hostname or IP address.

    hostname = "my-Sftp-Server-Domain-Or-IPAddress";
    port = 22;
    success = CkSFtp_Connect(sftp,hostname,port);
    if (success != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    //  Authenticate with the SSH server.  Chilkat SFTP supports
    //  both password-based authenication as well as public-key
    //  authentication.  This example uses password authenication.
    success = CkSFtp_AuthenticatePw(sftp,"myLogin","myPassword");
    if (success != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    //  After authenticating, the SFTP subsystem must be initialized:
    success = CkSFtp_InitializeSftp(sftp);
    if (success != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    //  Open a file on the server:
    handle = CkSFtp_openFile(sftp,"hamlet.xml","readOnly","openExisting");
    if (CkSFtp_getLastMethodSuccess(sftp) != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    //  Download the file:
    success = CkSFtp_DownloadFile(sftp,handle,"c:/temp/hamlet.xml");
    if (success != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    //  Close the file.
    success = CkSFtp_CloseHandle(sftp,handle);
    if (success != TRUE) {
        printf("%s\n",CkSFtp_lastErrorText(sftp));
        CkSFtp_Dispose(sftp);
        return;
    }

    printf("Success.\n");


    CkSFtp_Dispose(sftp);

    }

int main()
{
  ChilkatSample();
  return 0;
}

C# SFTP Upload from Byte[]

This example demonstrates how to open a remote file on an SSH/SFTP server,
write to the file, and then close it.  This is analogous to opening a local file,
writing to it, and closing it.  The SFTP protocol (i.e. Secure File Transfer over SSH),
follows the same concepts as typical file I/O programming -- i.e. open a file,
read, write, close, etc.).

// Assume at this point we already have a Chilkat.SFtp object
// connected to a server, authenticated, and InitializeSftp has
// already been called..


// To upload a binary file from Byte[], the procedure is to open the remote file,
// write the data, and then close the file.

// Open a remote file, returning a handle to the open file.
string handle = sftp.OpenFile("test.dat", "readWrite", "createTruncate");
if (!sftp.LastMethodSuccess)
    {
    textBox2.Text = sftp.LastErrorText;
    return;
    }

string text = "To live is the rarest thing in the world. Most people exist, that is all. -- Oscar Wilde\r\n";
byte[] bytes= System.Text.Encoding.UTF8.GetBytes(text);

// Write some data to the file.
bool success;
for (int i = 0; i < 20; i++)
    {
    // It is possible to write bytes:
    success = sftp.WriteFileBytes(handle, bytes);
    // It is also possible to write the string:
    if (success) success = sftp.WriteFileText(handle, "utf-8", text);

    if (!success)
        {
        textBox2.Text = sftp.LastErrorText;
        return;
        }
    }

// Close the remote file.
if (!sftp.CloseHandle(handle))
    {
    textBox2.Text = sftp.LastErrorText;
    return;
    }
 

C# TaskCompleted Event — Updating the UI from a Background Thread

This sample C# snippet demonstrates how to use the TaskCompleted event to be notified when an asynchronous method completes. Given that the event callback is in the background thread, any UI updates must occur on the main thread. This example demonstrates how to do it:

	private void taskCompletedToolStripMenuItem_Click(object sender, EventArgs e)
	    {
	    // Demonstrate an asynchronous Chilkat method call with a TaskCompleted event.
	    Chilkat.Http http = new Chilkat.Http();

	    http.OnTaskCompleted += http_OnTaskCompleted;

	    Chilkat.Task task = http.QuickGetStrAsync("http://www.chilkatsoft.com/");

	    // We can set the task.UserData property to identify this particular asynchronous call in the callback.
	    task.UserData = "chilkatHomePage";

	    // Runs the HTTP GET asynchronously on a background thread..
	    task.Run();
	    }

	// This event fires in the background thread. 
	// 
	void http_OnTaskCompleted(object sender, Chilkat.TaskCompletedEventArgs args)
	    {
	    Chilkat.Task task = args.Task;

	    // This event callback is running in the background thread.
	    // To update a UI element, we must be on the UI thread..
	    this.Invoke((MethodInvoker)delegate
		{
		    // The task.UserData can be used to identify the particular asynchronous method call
		    // that this callback belongs to.
		    if (task.UserData.Equals("chilkatHomePage"))
			{
			// An asychronous method is simply calling the corresponding synchronous method
			// in a background thread.  In this case, it is a call to QuickGetStr,
			// which returned a string, or it returned Nothing for failure.  This result is available
			// via task.GetResultString.  The LastErrorText for the background call 
			// is available in task.ResultErrorText
			string htmlPage = task.GetResultString();
			if (htmlPage == null)
			    {
			    textBox2.Text = task.ResultErrorText;
			    }
			else
			    {
			    textBox2.Text = htmlPage;
			    }
			}
		});
	    }
	}

(C++) Return Email Headers as iso-8859-15? (or any other charset)

Question:

In C++, is it somehow possible to specify a desired charset (like ISO-8859-15) when getting mail headers with POP3?

Answer:

Instead of calling the method that returns a “const char *” — which can return either utf-8 or ANSI (see this Chilkat blog post about the Utf8 property common to all Chilkat C++ classes), call the alternate method that returns the string in a CkString object.  You can then get the iso-8859-15 string from the CkString object.

Each Chilkat C++ method that returns a string has two versions — an upper-case version that returns the string in a CkString (always the last argument), and a lower-case version that returns a “const char *”.

For example, in the CkEmail class:

bool GetHeaderField(const char *fieldName, CkString &outFieldValue);
const char *getHeaderField(const char *fieldName);

The lower-case method returning a “const char *” returns a pointer to memory that may be overwritten in subsequent calls.  Therefore, make sure to copy the string to a safe place immediately before making additional calls on the same Chilkat object instance.  (Only methods that also return “const char *” would overwrite the memory from a previous call.)

The upper-case version of the method returns the string in a CkString object.  It is an output-only argument, meaning that the CkString contents are replaced, not appended.  To get the iso-8859-15 string from the CkString, call the getEnc method.  For example:

const char  *str_iso_8859_15 = outFieldValue.getEnc("iso-8859-15");

This returns a NULL-terminated string where each character is represented as a single byte using the iso-8859-15 encoding.

Chilkat C/C++ libraries now available for MAC OS X

The Chilkat C/C++ libraries are now available for MAC OS X. For the download link and more information, see http://www.chilkatsoft.com/installMacOSX.asp

Chilkat will soon release MAC OS X compatible builds for Java, Perl, Python, and Ruby. Following that, builds for the IOS (IPhone) will be released, along with Objective-C/C++ native libraries for both MAC OS X and IPhone.

Very simple C# SSH Shell Console Terminal

Here’s an example that demonstrates a rough start to creating a C# console SSH shell terminal (where the user can type commands and output from the remote command echos to the console:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace SshTerminalConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Chilkat.Ssh ssh = new Chilkat.Ssh();
            ssh.UnlockComponent("Test");

            //  Hostname may be an IP address or hostname:
            string hostname = "192.168.1.117";
            int port = 22;

            Console.WriteLine("Connecting...");

            //ssh.KeepSessionLog = true;
            bool success = ssh.Connect(hostname, port);
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();      
                return;
            }

            //  When reading, if no additional data arrives for more than
            //  5 seconds, then abort:
            ssh.IdleTimeoutMs = 5000;

            Console.WriteLine("Authenticating...");

            //  SSH Server Authentication
            //  If there is no login/password required, you must still call
            //  AuthenticatePw and use any values for login/password.
            success = ssh.AuthenticatePw("chilkat", "***");
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            Console.WriteLine("Opening Channel...");

            //  Open a session channel.
            int channelNum = ssh.OpenSessionChannel();
            if (channelNum < 0)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            //  Request a pseudo-terminal
            string termType;
            termType = "dumb";
            int widthInChars;
            widthInChars = 120;
            int heightInChars;
            heightInChars = 40;
            int pixWidth;
            pixWidth = 0;
            int pixHeight;
            pixHeight = 0;
            success = ssh.SendReqPty(channelNum, termType, widthInChars, heightInChars, pixWidth, pixHeight);
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            Console.WriteLine("Starting a shell...");

            //  Start a shell on the channel:
            success = ssh.SendReqShell(channelNum);
            if (success != true)
            {
                Console.WriteLine(ssh.LastErrorText + "\r\n");
                // Read so we can see the error before the console closes.
                string x = Console.ReadLine();
                return;
            }

            // Loop to read from the SSH channel, output to the console, and read keyboard input from the console.
            StringBuilder sb = new StringBuilder();
            while (true)
            {
                if (Console.KeyAvailable)
                {
                    ConsoleKeyInfo key = Console.ReadKey(true);
                    Console.Write(key.KeyChar);

                    switch (key.Key)
                    {
                        case ConsoleKey.Enter:
                            Console.WriteLine("");

                            sb.Append("\n");
                            success = ssh.ChannelSendString(channelNum, sb.ToString(), "ansi");
                            if (success != true)
                            {
                                Console.WriteLine(ssh.LastErrorText + "\r\n");
                                // Read so we can see the error before the console closes.
                                string x = Console.ReadLine();
                                return;
                            }

                            sb.Length = 0;
                            break;
                        default:
                            //Console.Write(key.KeyChar);
                            sb.Append(key.KeyChar);
                            break;
                    }

                }

                // Now check for incoming data from the SSH channel.
                int retval = ssh.ChannelPoll(channelNum, 10);
                if (retval == -1)
                {
                    Console.Write(ssh.LastErrorText);
                    Console.WriteLine("");
                    // Read so we can see the error before the console closes.
                    string x = Console.ReadLine();
                    return;
                }
                if (retval > 0)
                {
                    Console.Write(ssh.GetReceivedText(channelNum, "ansi"));
                }
                else
                {
                    // If data arrived, loop around and get more immediately.
                    // Otherwise wait 20ms.
                    System.Threading.Thread.Sleep(20);
                }

            }  

        }
    }
}