RPC call info_actions_folder seem to work almost perfectly

Use ccnpeek to test:
    ccnpeek -c /localhost/<your-user-name>/chronoshare/<folder>/info/actions/folder/<nonce>/%00
or
    ccnpeek -c /localhost/<your-user-name>/chronoshare/<folder>/info/actions/folder/<specific-folder>/<nonce>/%00

+ json_spirit used to format the whole message, not just parts

Change-Id: I40c15459a8ae0ef6278364c45e84e5cbd0b08241
diff --git a/src/state-server.cc b/src/state-server.cc
index 6f73950..c264edf 100644
--- a/src/state-server.cc
+++ b/src/state-server.cc
@@ -27,6 +27,7 @@
 #include "periodic-task.h"
 #include "simple-interval-generator.h"
 #include <boost/lexical_cast.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 INIT_LOGGER ("StateServer");
 
@@ -121,9 +122,77 @@
 //     }
 // }
 
-void debugAction (const Ccnx::Name &name, sqlite3_int64 seq_no, const ActionItem &action)
+void
+StateServer::formatActionJson (json_spirit::Array &actions,
+                               const Ccnx::Name &name, sqlite3_int64 seq_no, const ActionItem &action)
 {
-  std::cout << name << ", " << seq_no << ", " << action.filename () << std::endl;
+/*
+ *      {
+ *          "id": {
+ *              "userName": "<NDN-NAME-OF-THE-USER>",
+ *              "seqNo": "<SEQ_NO_OF_THE_ACTION>"
+ *          },
+ *          "timestamp": "<ACTION-TIMESTAMP>",
+ *          "filename": "<FILENAME>",
+ *
+ *          "action": "UPDATE | DELETE",
+ *
+ *          // only if update
+ *          "update": {
+ *              "hash": "<FILE-HASH>",
+ *              "timestamp": "<FILE-TIMESTAMP>",
+ *              "chmod": "<FILE-MODE>",
+ *              "segNum": "<NUMBER-OF-SEGMENTS (~file size)>"
+ *          },
+ *
+ *          // if parent_device_name is set
+ *          "parentId": {
+ *              "userName": "<NDN-NAME-OF-THE-USER>",
+ *              "seqNo": "<SEQ_NO_OF_THE_ACTION>"
+ *          }
+ *      }
+ */
+
+  using namespace json_spirit;
+  using namespace boost::posix_time;
+
+  Object json;
+  Object id;
+
+  id.push_back (Pair ("userName", boost::lexical_cast<string> (name)));
+  id.push_back (Pair ("seqNo",    seq_no));
+
+  json.push_back (Pair ("id", id));
+
+  json.push_back (Pair ("timestamp", to_iso_string (from_time_t (action.timestamp ()))));
+  json.push_back (Pair ("filename",  action.filename ()));
+  json.push_back (Pair ("action", (action.action () == 0) ? "UPDATE" : "DELETE"));
+
+  if (action.action () == 0)
+    {
+      Object update;
+      update.push_back (Pair ("hash", boost::lexical_cast<string> (Hash (action.file_hash ().c_str (), action.file_hash ().size ()))));
+      update.push_back (Pair ("timestamp", to_iso_string (from_time_t (action.mtime ()))));
+
+      ostringstream chmod;
+      chmod << setbase (8) << setfill ('0') << setw (4) << action.mode ();
+      update.push_back (Pair ("chmod", chmod.str ()));
+
+      update.push_back (Pair ("segNum", action.seg_num ()));
+      json.push_back (Pair ("update", update));
+    }
+
+  if (action.has_parent_device_name ())
+    {
+      Object parentId;
+      Ccnx::Name parent_device_name (action.parent_device_name ().c_str (), action.parent_device_name ().size ());
+      id.push_back (Pair ("userName", boost::lexical_cast<string> (parent_device_name)));
+      id.push_back (Pair ("seqNo",    action.parent_seq_no ()));
+
+      json.push_back (Pair ("parentId", parentId));
+    }
+
+  actions.push_back (json);
 }
 
 void
@@ -156,10 +225,36 @@
         folder = interest.getCompFromBackAsString (2);
       else // == 4
         folder = "";
+/*
+ *   {
+ *      "actions": [
+ *           ...
+ *      ],
+ *
+ *      // only if there are more actions available
+ *      "more": "<NDN-NAME-OF-NEXT-SEGMENT-OF-ACTION>"
+ *   }
+ */
 
-      m_actionLog->LookupActionsInFolderRecursively (debugAction, folder, offset*100, 100);
+      using namespace json_spirit;
+      Object json;
 
-      // m_ccnx->publishData (interest, "FAIL: Not implemented", 1);
+      Array actions;
+      bool more = m_actionLog->LookupActionsInFolderRecursively
+        (boost::bind (StateServer::formatActionJson, boost::ref(actions), _1, _2, _3),
+         folder, offset*10, 10);
+
+      json.push_back (Pair ("actions", actions));
+
+      if (more)
+        {
+          Ccnx::Name more = Name (interest.getPartialName (0, interest.size () - 1))(offset + 1);
+          json.push_back (Pair ("more", lexical_cast<string> (more)));
+        }
+
+      ostringstream os;
+      write_stream (Value (json), os, pretty_print | raw_utf8);
+      m_ccnx->publishData (interest, os.str (), 1);
     }
   catch (Ccnx::NameException &ne)
     {