repos | repos [dir] or [file] | Selects a new repository for interactive session |
publish | publish | Activates all (non-notifier) publishers in the repository, both push and pull |
publish [list] | Activates all (non-notifier) publishers with the given source, push only | |
publish [list] [key] | Activates all (non-notifier) publishers with the given source, for the single object named. | |
make | make | Publishes all pages, pulling data as necessary |
make [page] | Publishes a single page. | |
add | add [list] [file] | Adds an object to a list from the given file, and publishes. A '-' as filename indicates that the object's XML follows on stdin. |
del | del [list] [key] | Deletes the named object and publishes. (Note there's no need for an in-place version of this.) |
mod | mod [list] [key] [file] | Writes the given file to the key; the newly written object may have a new key. Publishes. A '-' as filename indicates that the object's XML follows on stdin. |
changed | changed [list] [key] | Signals a change in place to the given object. Publishes. |
diff | diff [list] [key] [file] | Checks the record-based difference between an object and a (presumably edited) file. As usual, '-' indicates stdin. |
changes | changes [date] | Lists those lists changed since the given date (timestamp, really, in ISO format). |
changes [date] [list] | Lists changes made to the specified list since the given date. | |
snapshot | snapshot [list] | Asks the list adaptor for a snapshot list and compares the result to the last snapshot; if changes are detected, the appropriate changelog notations are made. |
get | get [list] [key] | Retrieves the given object as XML (written to stdout). |
edit | edit [list] [key] | Retrieves the given object as an HTML edit form. |
display | display [list] [key] | Retrieves the default display HTML for the object. |
form | form [list] | Retrieves an empty (or defaulted) edit form for the list. |
defn | defn [list] | Retrieves a list's XML definition (for whatever structure it imposes on its members). |
define | define [list] [file] | Writes a new XML definition to a list from a file. Adaptors should know what to do to make this happen; some won't, though, and this will have no effect on lists stored with those adaptors. |
push | push [list1] [list2] | Pushes modified data from list1 to list2 (list2 may be omitted if it's included in the mirror attribute. |
push_all | push_all [list1] [list2] | Pushes all data from list1 to list2. |
pull | pull [list1] [list2] | Pulls modified data to list1 from list2. |
pull_all | pull_all [list1] [list2] | Pulls all data to list1 from list2. |
synch | synch [list1] [list2] | Pull, followed by a push. |
time | time | Gets server's notion of current time. |
echo | echo [arg] | Echoes a string back (makes scripting convenient). |
check | check [list] [key] | Tests existence of a given key. |
test | test [file] | Tests XML-readability of a file. |
submit | submit [list] [file] | Creates an object with the given file as its primary attachment. (- for stdin.) |
store | store [list] [filename] ([file]) | Same as submit, but specifies filename in controlled directory. |
attach | attach [list] [key] [field] [file] | Attaches a file to a named field in an existing object. |
retrieve | retrieve [list] [key] ([field]) | Retrieves attachment content (from primary attachment if field unnamed.) |
checkout | checkout [list] [key] ([field]) | Retrieves attachment and marks for update. |
getver | getver [list] [key] ([field]) | Gets current version of field (not just for attachments, but for any list value.) |
do | do [file]) | Performs an arbitrary action, subject to permissions. Filename '-' indicates XML following on stdin. |
#include <stdio.h> #include <string.h> #include "xmlapi.h" #include "xmlobj.h" #include "xml_template.h" #include "repmgr.h" #include "time.h" #ifdef WINDOWS #include "process.h" #include "direct.h" #else #include "unistd.h" #endif #ifndef WINDOWS void strlwr (char * str) { if (!str) return; while (*str) { if (*str >= 'A' && *str <= 'Z') { *str += 'a' - 'A'; } str++; } } #endif main (int argc, char * argv[]) { char config_path[512]; char commandline[1024]; char * chmark; FILE * config_file; FILE * file; XML * repository = NULL; XML * list = NULL; XML * scratch = NULL; int loopmode = 0; int args; char * contextid = NULL; char * command; char * arg1; char * arg2; char * arg3; char * arg4; int i; int silent_running = 0; int len; int no_initial_repository = 0; int argp = 1; /* We'll use this to skip flags like -r for location of the config file. */ #define argsleft (argc - argp) XML * mark; XML * mark2; XML * holder; XML * defn; struct tm * timeptr; time_t julian; if (argc < 2) { command = "loop"; argp = argc; } arg1 = "site.opm"; while (argsleft && *argv[argp] == '-') { if (!strcmp (argv[argp], "-r")) { argp++; arg1 = argv[argp]; argp++; } else if (!strcmp (argv[argp], "-s")) { argp++; silent_running = 1; } else if (!strcmp (argv[argp], "-c")) { argp++; contextid = argv[argp]; argp++; } } *config_path = '\0'; if (-1 == chdir(arg1)) { strcpy (commandline, arg1); chmark = strrchr (commandline, '/'); if (!chmark) chmark = strrchr (commandline, '\\'); if (!chmark) { strcpy (config_path, commandline); } else { strcpy (config_path, chmark + 1); *chmark = '\0'; if (-1 == chdir (commandline)) { fprintf (silent_running ? stderr : stdout, "-100: Can't find directory %s\n", commandline); no_initial_repository = 1; } } } if (!no_initial_repository) { if (!*config_path) strcpy (config_path, "site.opm"); config_file = fopen (config_path, "r"); if (!config_file) { /* && complain_if_no_file) {*/ fprintf (silent_running ? stderr : stdout, "-101: Can't find repository file '%s'\n", config_path); no_initial_repository = 1; } } if (!no_initial_repository) { repository = xml_read_error (config_file); if (xml_is (repository, "xml-error")) { fprintf (silent_running ? stderr : stdout, "-200: Error reading repository definition '%s'; '%s' in line %s\n", config_path, xml_attrval (repository, "message"), xml_attrval (repository, "line")); xml_free (repository); repository = NULL; } else { repos_open (repository, NULL, "cmdline"); if (*xml_attrval (repository, "error-state")) { fprintf (silent_running ? stderr : stdout, "-201: Error opening repository -- %s\n", xml_attrval (repository, "error-state")); xml_free (repository); repository = NULL; } else { if (!silent_running) printf ("+000: Repository open.\n"); } } fclose (config_file); } if (contextid && repository) { if (repos_context_switch (repository, contextid)) { if (!silent_running) printf ("Context %s loaded\n", contextid); } } command = "loop"; if (argsleft) command = argv[argp++]; if (!command) command = "loop"; args = argsleft; arg1 = arg2 = arg3 = arg4 = NULL; if (argsleft) arg1 = argv[argp++]; if (argsleft) arg2 = argv[argp++]; if (argsleft) arg3 = argv[argp++]; if (argsleft) arg4 = argv[argp++]; do { if (loopmode) { /* printf ("\nReady!%s\n", repository ? "" : " (no repository open)"); */ fflush (stdout); if (!fgets(commandline, 1024, stdin)) { command = "bye"; } else { command = strtok (commandline, " \r\n\t"); if (!command) command = "null"; args = 0; arg1 = strtok (NULL, " \r\n\t"); if (arg1) args++; arg2 = strtok (NULL, " \r\n\t"); if (arg2) args++; arg3 = strtok (NULL, " \r\n\t"); if (arg3) args++; arg4 = strtok (NULL, " \r\n\t"); if (arg4) args++; } } strlwr (command); if (!strcmp (command, "help")) { See Displaying a list of commands } else if (!strcmp (command, "repos")) { See Opening repositories } else if (!strcmp (command, "publish")) { See Publishing objects (pushing data) } else if (!strcmp (command, "make")) { See Publishing pages (pulling data) } else if (!strcmp (command, "add")) { See Adding objects to lists } else if (!strcmp (command, "del")) { See Deleting objects from lists } else if (!strcmp (command, "mod")) { See Modifying objects } else if (!strcmp (command, "merge")) { See Merging objects } else if (!strcmp (command, "changed")) { See Modifying objects in place } else if (!strcmp (command, "diff")) { See Checking differences } else if (!strcmp (command, "list")) { See Listing objects } else if (!strcmp (command, "changes")) { See Listing changes } else if (!strcmp (command, "snapshot")) { See Taking a snapshot } else if (!strcmp (command, "get")) { See Retrieving objects } else if (!strcmp (command, "check")) { See } else if (!strcmp (command, "test")) { See Checking XML well-formedness } else if (!strcmp (command, "edit")) { See Retrieving editor HTML } else if (!strcmp (command, "display")) { See Display objects as HTML } else if (!strcmp (command, "form")) { See Building an empty form for object creation } else if (!strcmp (command, "defn")) { See Retrieving list structure definitions } else if (!strcmp (command, "define")) { See Imposing or changing list structure } else if (!strcmp (command, "push")) { See Pushing data to a remote list } else if (!strcmp (command, "push_all")) { See Pushing all data to a remote list } else if (!strcmp (command, "pull")) { See Pulling data from a remote list } else if (!strcmp (command, "pull_all")) { See Pulling all data from a remote list } else if (!strcmp (command, "synch")) { See Synching data with a remote list } else if (!strcmp (command, "submit")) { See Submitting a document } else if (!strcmp (command, "store")) { See Storing a document } else if (!strcmp (command, "attach")) { See Attaching a document } else if (!strcmp (command, "retrieve")) { See Retrieving a document } else if (!strcmp (command, "checkout")) { See Checking a document out for update } else if (!strcmp (command, "getver")) { See Getting the version of a field or attachment } else if (!strcmp (command, "time")) { See Marking time } else if (!strcmp (command, "echo")) { if (!silent_running) printf ("+000: %s ++done++\n", arg1); } else if (!strcmp (command, "auth")) { See Authenticating and retrieving users } else if (!strcmp (command, "ingroup")) { See Testing group membership } else if (!strcmp (command, "context")) { See Storing and switching contexts } else if (!strcmp (command, "tasks")) { See Listing active tasks } else if (!strcmp (command, "todo")) { See List active tasks for current user } else if (!strcmp (command, "xact")) { See Creating or loading a transaction } else if (!strcmp (command, "commit")) { See Committing a transaction } else if (!strcmp (command, "process")) { See Performing asynchronous processing } else if (!strcmp (command, "set")) { See Storing session values } else if (!strcmp (command, "read")) { See Retrieving session values } else if (!strcmp (command, "do")) { See Performing an action } else if (!strcmp (command, "loop")) { if (!silent_running) printf ("repmgr v1.0 listening: type 'help' for help.\n++done++\n"); loopmode = 1; } else if (!strcmp (command, "bye")) { if (loopmode) { loopmode = 0; if (!silent_running) printf ("+000: Ciao ragazzo. ++done++\n"); } } else if (!strcmp (command, "serve")) { /* Reserved for later: set up a socket listener. */ } else if (!strcmp (command, "null")) { /* Does nothing. */ } else { fprintf (silent_running ? stderr : stdout, "-010: Unknown command %s. ++done++\n", command); } if (list) xml_free (list); list = NULL; if (scratch) xml_free (scratch); scratch = NULL; } while (loopmode); if (repository) xml_free (repository); } |
printf ("repmgr (c) 2001-2005, Vivtek, under GPL.\n"); printf ("-----------------------------------\n"); printf ("Repository definition: %s%s\n", config_path, repository ? "" : " (not open)"); printf ("Compiled: " __DATE__ " " __TIME__ "\n"); printf ("See http://www.vivtek.com/wftk/doc/repmgr/ for more information.\n"); printf ("\n"); if (!loopmode) printf ("Usage: repmgr [command] [args]\n"); printf ("repos [list] or [file] : Open new repository\n"); printf ("publish : Activate all non-notification publishers and pages\n"); printf ("publish [list] : Activate all non-notification publishers for list\n"); printf ("publish [list] [key] : Publish single object\n"); printf ("make : Publish all *pages* (pulls data)\n"); printf ("make [page] : Publish a single page (pulls data)\n"); printf ("add [list] [file] : Add object from file (use '-' to indicate stdin)\n"); printf ("del [list] [key] : Delete named object\n"); printf ("mod [list] [file] : Modify object from file (may duplicate key) (use '-' to indicate stdin)\n"); printf ("mod [list] [file] [key] : Modify if key known (safer) (use '-' to indicate stdin)\n"); printf ("merge [list] [file] [key] : Merge objects (key optional) (use '-' to indicate stdin)\n"); printf ("changed [list] [key] : Log and publish object added or changed behind the scenes\n"); printf ("diff [list] [key] [file] : Check difference between object and file\n"); printf ("test [file] : Test XML well-formedness of a file\n"); printf ("list [list] : List keys for objects\n"); printf ("changes [date] : List changed lists since date (date in ISO format, e.g. 2001-12-13T11:12:52\n"); printf ("changes [date] [list] : List changes to a list since date\n"); printf ("get [list] [key] : Retrieve XML object\n"); printf ("edit [list] [key] : Retrieve XML object as HTML form\n"); printf ("display [list] [key] : Retrieve XML object as HTML display\n"); printf ("auth [user] [password] : Authenticate/retrieve user\n"); printf ("ingroup [user] [group] : Test group membership/retrieve group\n"); printf ("tasks : List entire task index\n"); printf ("tasks [list] : List tasks for a list\n"); printf ("tasks [list] [key] : List tasks for a specific object\n"); printf ("todo : List all tasks assigned to current user\n"); printf ("xact : Start a transaction attached to the current session\n"); printf ("xact [key] : Attach an existing transaction to the current session\n"); printf ("commit : Commit the current transaction\n"); printf ("process : Perform all outstanding asynchronous processing\n"); printf ("process [list] : Perform asynchronous processing for the named list\n"); printf ("process [list] [key] : Perform asynchronous processing for the specified object\n"); printf ("form [list] : Build empty form for list\n"); printf ("defn [list] : Retrieve XML structure definition\n"); printf ("define [list] : Write new XML structure definition\n"); printf ("push [list] [remote] : Push modifications to remote list\n"); printf ("push_all[list] [remote] : Push all data to remote list\n"); printf ("pull [list] [remote] : Pull modifications from remote list\n"); printf ("pull_all[list] [remote] : Pull all data from remote list\n"); printf ("synch [list] [remote] : Pull modificiations, then push\n"); printf ("submit [list] [file] : Create object using file contents for primary attachment ('-' for stdin)\n"); printf ("store [list] [fname] [file]: Same, but specifying a local storage filename\n"); printf ("attach [list] [key] [fld] [file]: Writes attachment to a given field of an existing object\n"); printf ("retrieve[list] [key] [fld] [file]: Retrieves an attachment's content\n"); printf ("checkout[list] [key] [fld] : Same, but marks the version for update\n"); printf ("getver [list] [key] [fld] : Retrieves version level of a field\n"); printf ("auth [user] [password] : Authorize user\n"); printf ("ingroup [user] [groupid] : Check group membership\n"); printf ("context ([id]) : save or switch session context\n"); printf ("set [name] [value] : save context value\n"); printf ("get [name] : retrieve context value\n"); printf ("do [file] : execute an action (use '-' to indicate stdin)\n"); printf ("time : Show server's local time\n"); printf ("++done++\n\n"); |
if (args < 1) { fprintf (silent_running ? stderr : stdout, "repmgr: No directory or file supplied.\n"); continue; } if (repository) xml_free (repository); repository = NULL; *config_path = '\0'; if (-1 == chdir(arg1)) { chmark = strrchr (arg1, '/'); if (!chmark) chmark = strrchr (arg1, '\\'); if (!chmark) { strcpy (config_path, arg1); } else { strcpy (config_path, chmark + 1); *chmark = '\0'; if (-1 == chdir (arg1)) { fprintf (silent_running ? stderr : stdout, "-100: Can't find directory %s ++done++\n", arg1); continue; } } } if (!*config_path) strcpy (config_path, "site.opm"); config_file = fopen (config_path, "r"); if (!config_file) { /* && complain_if_no_file) {*/ printf ("-101: Can't find repository file '%s' ++done++\n", config_path); continue; } repository = xml_read_error (config_file); if (xml_is (repository, "xml-error")) { printf ("-200: Error reading repository definition '%s'; '%s' in line %s ++done++\n", config_path, xml_attrval (repository, "message"), xml_attrval (repository, "line")); xml_free (repository); repository = NULL; } else { repos_open (repository, NULL, "cmdline"); if (*xml_attrval (repository, "error-state")) { printf ("-201: Error opening repository -- %s ++done++\n", xml_attrval (repository, "error-state")); xml_free (repository); repository = NULL; } else { printf ("+000: Repository open. ++done++\n"); } } fclose (config_file); |
if (!repository) { printf ("-000: No repository open. ++done++\n"); continue; } if (args < 1) { repos_publish_all (repository); printf ("+000: OK ++done++\n"); continue; } if (args < 2) { repos_publish_list (repository, arg1); printf ("+000: OK ++done++\n"); continue; } repos_publish_obj (repository, arg1, arg2); printf ("+000: OK ++done++\n"); |
if (!repository) { printf ("-000: No repository open. ++done++\n"); continue; } if (args < 1) { repos_publish_pages (repository); printf ("+000: OK ++done++\n"); continue; } repos_publish_page (repository, arg1); printf ("+000: OK ++done++\n"); |
if (!repository) { fprintf (silent_running ? stderr : stdout, "-000: No repository open. ++done++\n"); continue; } if (args < 1) { fprintf (silent_running ? stderr : stdout, "-001: Usage: do [action] {output} ++done++\n"); continue; } if (args == 1) { args = 2; arg2 = "-"; } if (*arg1 == '-') { /* Get action from stdin. */ scratch = xml_create ("s"); xml_set (scratch, "s", ""); xml_set (scratch, "output", arg2); /* Stash output */ arg2 = (char *) xml_attrval (scratch, "output"); while (fgets(commandline, 1024, stdin)) { if (commandline[0] == '>' && commandline[1] == '>') break; xml_attrcat (scratch, "s", commandline); } mark = xml_parse (xml_attrval (scratch, "s")); if (xml_is (mark, "xml-error")) { fprintf (silent_running ? stderr : stdout, "-200: Error reading input; '%s' in line %s ++done++\n", xml_attrval (mark, "message"), xml_attrval (mark, "line")); xml_free (mark); mark = NULL; } if (!mark) continue; } else { file = fopen (arg1, "r"); if (!file) { fprintf (silent_running ? stderr : stdout, "-201: Unable to open file %s ++done++\n", arg1); continue; } mark = xml_read_error (file); fclose (file); if (xml_is (mark, "xml-error")) { fprintf (silent_running ? stderr : stdout, "-200: Error reading file '%s'; '%s' in line %s ++done++\n", arg1, xml_attrval (mark, "message"), xml_attrval (mark, "line")); xml_free (mark); continue; } } /* TODO: these outputs assume the action is authorized for immediate execution. The messages should at least be errors in case of failed authorization, but ideally would include something appropriate in case of deferred approval. */ if (*arg2 == '-') { repos_action_do (repository, mark); if (!silent_running) printf ("+200: OK, XML follows.\n"); xml_write (stdout, mark); if (!silent_running) printf ("\n>>\n"); if (!silent_running) printf ("+000: OK ++done++\n"); } else if (*arg2 == '!') { repos_action_do (repository, mark); repos_add (repository, arg2 + 1, mark); if (!silent_running) printf ("+000: OK - %s ++done++\n", repos_getkey (repository, arg1, mark)); } else { file = fopen (arg2, "w"); if (!file) { fprintf (silent_running ? stderr : stdout, "-201: Unable to open file %s; no action taken ++done++\n", arg2); } else { repos_action_do (repository, mark); xml_write (file, mark); fclose (file); if (!silent_running) printf ("+000: OK ++done++\n"); } } xml_free (mark);
Deleting objects from lists Deletion, of course, acts on a key, not a file.
Modifying objects And with modification, we've gotten tricky again, with our little multiple-arity thing there.
Merging objects Merging is basically exactly like modification as far as the command line is concerned.
Modifying objects in place For easy integration with external scripts and such, we want to be able to tell the system about it when we've modified an object directly (perhaps by editing its file, or making a change to a database directly -- whatever.) We can't put it into the "mod" command because there's no good way to indicate that. So we have a new command for it. The commands "changed" and "snapshot" are pretty much mutually exclusive. Since "changed" does nothing to update the current snapshot, you'll end up noting (and logging, and publishing) each modification twice, which won't do anybody much good. If you're going to use "snapshot", stick with it. However, since some data sources may not be able to do snapshots, there are still situations where "changed" and "del" should be used together to do things individually.
Checking XML well-formedness This is a simple diagnostic -- it just loads an arbitrary file and tells you whether it worked or not.
Checking differences This is something kinda neat -- it compares two XML records and gives a field-by-field diff. In this variety of diff, the textual aspect of the XML is largely ignored; whitespace doesn't count and even the order of fields in the record doesn't count as a change. Only attributes and values count.
Listing objects To list objects, we just get a list using the library, then show the keys for the returned list.
Taking a snapshot The idea behind a snapshot is simple: we record the current state of a list in simplified form, then if its contents are changed outside the framework, we are able to compare the current state with a past state and note that items have been added, deleted, or (in some cases) modified. Modification is easy to detect on the basis of the file timestamps in a directory, for instance, or a database table may impose a last-edited restriction, or we may use some sort of checksum scheme. The storage adaptor makes the decision as to what (if anything) can be used to detect modification. However, by keeping a snapshot list, we are at least absolutely certain of detecting additions and deletions, because those affect the list of keys present.
Listing changes To list changes, we have a special command. It comes in two forms: one lists the lists which have been changed, the other lists the actual changes to a particular list. Each returns a series of text lines from the command line, even though the API returns (of course) an XML structure. The date is given in ISO format -- but since I use a separating space in my dates in the log (for readability) I realized that such a date can't actually be given in a space-delimited command line! So if the date is longer than 10 characters, we set the 11th character to a space so it'll match our expectations. This allows the command-line date to be separated with a 'T' (the ISO's recommendation) or whatever other non-space character the user might choose to use.
Retrieving objects To retrieve an object, we simply retrieve it using the library, then write its XML to stdout. This isn't meant to be brain surgery.
Authenticating and retrieving users User authentication works with plaintext passwords. TODO: fix same. Authentication also returns a description of the user (name, etc.) as an xmlobj object.
Testing group membership Not much to say about this one, except that the return (if the user is in the group) is the group object.
Storing and switching contexts The session or context can be stored as a means of saving named values accumulated during a session. At some point, the context will also maintain contextual values such as the id of the last list referred to, etc.
Storing session values This primitive command line can't deal with values with spaces, which is less than perfectly useful, but it's a start.
Retrieving session values Again: the command line interface as currently constituted can't deal with spaces well. TODO: Really have to write a command-line parser....
Listing active tasks The "tasks" command is equivalent in execution to "list _tasks" -- except that where the latter displays only keys, this command also displays task labels, assignments, and maybe other information as we later find appropriate. It is formatted for human consumption rather than for machine readability. Really, I suppose, it exemplifies a modality of list retrieval which would be of great benefit if generalized: the ability to specify a formatting string of some sort for list returns. Anyway, the formatting of this list is straight out of the wftk_util command-line utility for the wftk core.
List active tasks for current user The "todo" command is just like the "tasks" command, except it uses the _todo list, which filters for the current authuser before returning results.
Creating or loading a transaction Starts a transaction attached to the current session, or attaches an existing transaction to the current session. TODO: implement.
Committing a transaction Commits the current transaction. TODO: implement.
Performing asynchronous processing Fronts for repos_process to enable easy kickoff of asynchronous processing from the command line as e.g. a cronjob. TODO: implement.
Retrieving editor HTML
Display objects as HTML
Building an empty form for object creation
Retrieving list structure definitions
Imposing or changing list structure And here we have to read and parse a file again.
Pushing data to a remote list This is almost too easy. And the other synch commands are identical to it.
Pushing all data to a remote list This is almost too easy. And the other synch commands are identical to it.
Pulling data from a remote list This is almost too easy. And the other synch commands are identical to it.
Pulling all data from a remote list This is almost too easy. And the other synch commands are identical to it.
Synching data with a remote list This is almost too easy. And the other synch commands are ... wait. I have this really strong feeling of deja vu.
Submitting a document Submitting a document first creates an object of the named list, then attaches the incoming document to it. If the content is specified on the command line, the protocol allows for headers which can set arbitrary field values in the new object. TODO: implement.
Storing a document Storing a document is identical to submitting (in that it creates an object) but includes a filename for the incoming document. This makes it easy for the localdir storage adaptor to manage a local directory of files (such as images) by treating them as attachments. TODO: implement.
Attaching a document This is the plain-vanilla attachment command, which attaches a document to an already existing object. This may entail the disposal of pre-existing attachments (perhaps with version control) or it may not. This logic is all handled in the repmgr library, unless the content to be attached is supplied on the command line; in that case, the content handling is done here. Note that if the command-line option is used, the protocol allows for headers which can specify values for arbitrary fields.
Retrieving a document Document retrieval is exactly what you'd think it is: it reads the content of an attachment. If aimed at a normal field, it'll just retrieve its value.
Checking a document out for update Checking a document out puts your user name on it. Since I haven't yet implemented user authentication, this is just retrieval at the moment. TODO: implement.
Getting the version of a field or attachment This is effectively a NOOP for now, as I don't have list values implemented (and thus no versions). TODO: implement.
Marking time The 'time' command is used to get the server time of a repository -- that is, the local time of the server where the repository is located. Note that since this command should be functional even when no repository is open (so that a server can be opened without a local repository and still return its local time), there is code to format a time even in the absence of an open repository. However, if possible, the repos_mark_time function is called to retrieve the time.
|