diff options
author | goodale <goodale@1faa4e14-9dd3-4be0-9f0e-ffe519881164> | 2000-09-17 13:02:27 +0000 |
---|---|---|
committer | goodale <goodale@1faa4e14-9dd3-4be0-9f0e-ffe519881164> | 2000-09-17 13:02:27 +0000 |
commit | 3911e5fe8ce0a87db2fbab4795bc03da5fe12556 (patch) | |
tree | 711e9c631912ef46c48cea3d0025770758726bc8 | |
parent | 820f6dc61d99821a1e0b1abeb2910bc384869603 (diff) |
Added authentification for setting parameters and a control page.
Unless one has previously authenticated by going to /control.html
all paramters are read only. The default username and password are both
"anon". I also added a hack so these don't get displayed on the web
page - this should go away when we have parameter tags.
Added http_Content.h which currently contains a function for
registering a link to be displayed elsewhere. It takes the URL,
the link name, a longer description line, and a flag. Currently the
flag should be set to HTTP_QUICKLINK to get things displayed on the
quicklinks on some pages.
Still need to add a function which will allow other thorns access to
this data.
Tom
git-svn-id: http://svn.cactuscode.org/arrangements/CactusConnect/HTTPD/trunk@35 1faa4e14-9dd3-4be0-9f0e-ffe519881164
-rw-r--r-- | param.ccl | 17 | ||||
-rw-r--r-- | src/Content.c | 582 | ||||
-rw-r--r-- | src/http_Content.h | 30 |
3 files changed, 566 insertions, 63 deletions
@@ -26,6 +26,23 @@ BOOLEAN pause "Pause ?" STEERABLE = ALWAYS { } "no" +# Username and password for controlling cactus +STRING user "The username for Cactus Control " +{ + ".+" :: "Any name of one or more characters" +} "anon" + +STRING password "The password for Cactus Control" +{ + ".*" :: "Any password" +} "anon" + +KEYWORD encryption_scheme "How the password is encrypted" +{ + "none" :: "Not encrypted" + "crypt" :: "crypt(3) (standard UNIX passwd format)" +} "none" + ################################################################## # Tuning parameters diff --git a/src/Content.c b/src/Content.c index c423d64..993747a 100644 --- a/src/Content.c +++ b/src/Content.c @@ -27,7 +27,10 @@ #include "http_Auth.h" #include "http_Steer.h" +#include "http_Content.h" + #include "cctk_Arguments.h" +#include "cctk_Parameters.h" static char *rcsid = "$Header$"; @@ -44,6 +47,15 @@ struct httpStaticPage char *mime_type; }; +struct httpLink +{ + struct httpLink *next; + char *URL; + char *name; + char *description; + int flags; +}; + /******************************************************************** ********************* Local Routine Prototypes ********************* ********************************************************************/ @@ -57,10 +69,12 @@ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data); static int ShowStaticPage(cGH *cctkGH, httpRequest *request, void *data); -static int AuthPage(cGH *cctkGH, httpRequest *request, void *data); - static int CompareStrings(const void *string1, const void *string2); +static int ControlPage(cGH *cctkGH, httpRequest *request, void *data); +static int ControlSet(cGH *cctkGH, httpRequest *request); +static int ControlTerminationPage(cGH *cctkGH, httpRequest *request); + /******************************************************************** ********************* Other Routine Prototypes ********************* ********************************************************************/ @@ -69,6 +83,8 @@ static int CompareStrings(const void *string1, const void *string2); ********************* Local Data ***************************** ********************************************************************/ +static struct httpLink *ContentLinks = NULL; + /******************************************************************** ********************* External Routines ********************** ********************************************************************/ @@ -110,6 +126,7 @@ void HTTP_ContentWork(CCTK_ARGUMENTS) @@*/ int HTTP_RegisterPages(void) { + DECLARE_CCTK_PARAMETERS #ifdef HTTP_DEBUG printf("Registering index.html\n"); #endif @@ -121,16 +138,78 @@ int HTTP_RegisterPages(void) RegisterParameterPages(); - /* Register a test authentication page. */ + /* Register parameter control stuff. */ + + HTTP_RegisterPage("/control.html", ControlPage, NULL); - HTTP_RegisterPage("/auth_page", AuthPage, NULL); + HTTP_ContentLink("/control.html", "Cactus Control", + "Control Panel for this run", + HTTP_QUICKLINK); - HTTP_AuthAddUser("user","goodale","foo","none"); + HTTP_AuthAddUser("user",user,password,encryption_scheme); /* Register images */ RegisterImages(); } + /*@@ + @routine HTTP_ContentLink + @date Sun Sep 17 13:17:56 2000 + @author Tom Goodale + @desc + Register content links. + @enddesc + @calls + @calledby + @history + + @endhistory + +@@*/ +int HTTP_ContentLink(const char *URL, + const char *name, + const char *description, + int flags) +{ + int retval; + struct httpLink *link; + struct httpLink *last; + struct httpLink *current; + + link = (struct httpLink *)malloc(sizeof(struct httpLink)); + + if(link) + { + link->URL = Util_Strdup(URL); + link->name = Util_Strdup(name); + link->description = Util_Strdup(description); + link->flags = flags; + link->next = NULL; + + /* Put on list */ + if(ContentLinks) + { + for(current=ContentLinks; current; current = current->next) + { + last = current; + } + last->next = link; + } + else + { + ContentLinks = link; + } + + retval = 0; + } + else + { + retval = -1; + } + + return retval; +} + /******************************************************************** ********************* Local Routines ************************* ********************************************************************/ @@ -212,6 +291,7 @@ static int MainPage(cGH *cctkGH, httpRequest *request, void *data) { int retval; char message[4098]; + struct httpLink *link; /* Status message */ strcpy(message,"HTTP/1.0 200 OK\r\n"); @@ -231,6 +311,30 @@ static int MainPage(cGH *cctkGH, httpRequest *request, void *data) /* Write out the main header part */ HTTP_Write(request, cactus_mainheader, strlen(cactus_mainheader)); + strcpy(message, "<center><h1>Simulation Home Page</h1></center>"); + + /* ADD QUICK LINKS (e.g. FOR PALM) */ + + if(ContentLinks) + { + strcpy(message, "<center>Quick links: "); + + for(link = ContentLinks; link; link=link->next) + { + if(link->flags & HTTP_QUICKLINK) + { + sprintf(message, + "%s[<A HREF=\"%s\">%s</a>]", + message, + link->URL, + link->name); + } + } + strcat(message,"</center>\n<br>\n"); + HTTP_Write(request, message, strlen(message)); + } + + /* Some blurb */ strcpy(message, "<br>" "<center><table cellspacing=5 cellpadding=5 border=0><tr><td valign=top>" @@ -373,6 +477,10 @@ static int RegisterParameterPages(void) HTTP_RegisterPage("/Parameters/index.html", MainParameterPage, NULL); + HTTP_ContentLink("/Parameters/index.html", "Parameters", + "Parameter Informatiiona and Control", + HTTP_QUICKLINK); + for (i = 0; i < CCTK_NumCompiledThorns (); i++) { thorn = CCTK_CompiledThorn(i); @@ -475,6 +583,10 @@ static int MainParameterPage(cGH *cctkGH, httpRequest *request, void *data) return retval; } +static const char *notauthorized_page = +"<HTML>\n<HEAD><TITLE>Error 401: Not Authorized</TITLE></HEAD>\ +<BODY>You are not authorized to access this page</BODY>\n<HTML>\n"; + /*@@ @routine ThornParameterPage @date Sat Sep 16 15:13:55 2000 @@ -509,37 +621,85 @@ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data) const char *prefix; const httpArg *argument; + int notauthorised; + int readonly; + thorn = (const char *)data; + notauthorised = HTTP_AuthenticateBasic(request, "user"); + + readonly = notauthorised; + if(request->n_arguments > 0) { /* This is a parameter set request */ - /* Queue parameters for steering */ - first = 1; - while(argument = HTTP_ArgumentWalk(request, first)) + if(!notauthorised) { - first = 0; - fprintf(stderr, "Setting %s::%s to %s\n", thorn, argument->arg, argument->value); - HTTP_SteerQueue(thorn, argument->arg, argument->value); - } + if(!readonly) + { + /* Queue parameters for steering */ + first = 1; + while(argument = HTTP_ArgumentWalk(request, first)) + { + first = 0; + fprintf(stderr, "Setting %s::%s to %s\n", thorn, argument->arg, argument->value); + HTTP_SteerQueue(thorn, argument->arg, argument->value); + } + + /* Now redirect the browser to the normal page */ + /* Status message */ + if(request->http_major_version < 1 || + (request->http_major_version == 1 && request->http_minor_version < 1)) + { + /* Older browsers don't understand 303 */ + strcpy(message,"HTTP/1.0 302 Found\r\n"); + } + else + { + strcpy(message,"HTTP/1.0 303 See Other\r\n"); + } - /* Now redirect the browser to the normal page */ - /* Status message */ - if(request->http_major_version < 1 || - (request->http_major_version == 1 && request->http_minor_version < 1)) - { - /* Older browsers don't understand 303 */ - strcpy(message,"HTTP/1.0 302 Found\r\n"); + sprintf(message, "%sLocation: /Parameters/%s/\r\n\r\n", message, thorn); + + HTTP_Write(request, message, strlen(message)); + } + else + { + /* Redirect the browser to the normal page */ + /* Status message */ + if(request->http_major_version < 1 || + (request->http_major_version == 1 && request->http_minor_version < 1)) + { + /* Older browsers don't understand 303 */ + strcpy(message,"HTTP/1.0 302 Found\r\n"); + } + else + { + strcpy(message,"HTTP/1.0 303 See Other\r\n"); + } + + sprintf(message, "%sLocation: /Parameters/%s/\r\n\r\n", message, thorn); + + HTTP_Write(request, message, strlen(message)); + } } else { - strcpy(message,"HTTP/1.0 303 See Other\r\n"); - } - - sprintf(message, "%sLocation: /Parameters/%s/\r\n\r\n", message, thorn); + strcpy(message,"HTTP/1.0 401 Unauthorized\r\n"); + + HTTP_Write(request, message, strlen(message)); - HTTP_Write(request, message, strlen(message)); + strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n"); + + HTTP_Write(request, message, strlen(message)); + + strcpy(message,"Content-Type: text/html\r\n\r\n"); + + HTTP_Write(request, message, strlen(message)); + + HTTP_Write(request, notauthorized_page, strlen(notauthorized_page)); + } } else @@ -591,9 +751,12 @@ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data) HTTP_Write(request, message, strlen(message)); - sprintf(message,"<FORM ACTION=\"/Parameters/%s/\"><TR><TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE=SUBMIT VALUE=\"Update all parameters\"></TD></TR>\n", thorn); - HTTP_Write(request, message, strlen(message)); - + if(!readonly) + { + sprintf(message,"<FORM ACTION=\"/Parameters/%s/\"><TR><TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE=SUBMIT VALUE=\"Update all parameters\"></TD></TR>\n", thorn); + HTTP_Write(request, message, strlen(message)); + } + /* Walk through all parameters of given implementation. */ first = 1; @@ -614,7 +777,7 @@ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data) prefix = CCTK_ThornImplementation (pData->thorn); } - if (pData->steerable == CCTK_STEERABLE_ALWAYS) + if (pData->steerable == CCTK_STEERABLE_ALWAYS && !readonly) { sprintf(message, "%s<TR><TD align=left valign=center><font color=red>%s::%s</font></TD>" @@ -624,10 +787,17 @@ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data) } else { - sprintf(message, - "%s<TR><TD align=left valign=center>%s::%s</TD>" - "<TD>%s</TD></TR>\n", - message, prefix,pData->name, value); + /* FIXME: This is a hack - should put in parameter tags. */ + if(strcmp(thorn,CCTK_THORNSTRING) || + (strcmp(pData->name,"user") && + strcmp(pData->name,"password") && + strcmp(pData->name,"encryption_scheme"))) + { + sprintf(message, + "%s<TR><TD align=left valign=center>%s::%s</TD>" + "<TD>%s</TD></TR>\n", + message, prefix,pData->name, value); + } } free (value); } @@ -635,10 +805,15 @@ static int ThornParameterPage(cGH *cctkGH, httpRequest *request, void *data) } - strcpy(message, - "<TR><TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE=SUBMIT VALUE=\"Update all parameters\"></TD></TR>\n" - "</TABLE><P></BLOCKQUOTE>\n" - "</FORM>\n"); + if(!readonly) + { + strcpy(message, + "<TR><TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE=SUBMIT VALUE=\"Update all parameters\"></TD></TR>\n" + "</FORM>\n"); + HTTP_Write(request, message, strlen(message)); + } + + strcpy(message, "</TABLE><P></BLOCKQUOTE>\n"); HTTP_Write(request, message, strlen(message)); } @@ -744,25 +919,12 @@ static int ShowStaticPage(cGH *cctkGH, httpRequest *request, void *data) } -/****************************************************************************** - ********************** Authentication test page ****************************** - ******************************************************************************/ - - -static const char *notauthorized_page = -"<HTML>\n<HEAD><TITLE>Error 401: Not Authorized</TITLE></HEAD>\ -<BODY>You are not authorized to access this page</BODY>\n<HTML>\n"; - -static const char *authorized_page = -"<HTML>\n<HEAD><TITLE>Authorized</TITLE></HEAD>\ -<BODY>Congratulations !</BODY>\n<HTML>\n"; - /*@@ - @routine AuthPage - @date Fri Sep 15 12:52:37 2000 + @routine ControlPage + @date Sun Sep 17 14:37:59 2000 @author Tom Goodale @desc - Test page for authentication. + Cactus Control Panel @enddesc @calls @calledby @@ -771,38 +933,113 @@ static const char *authorized_page = @endhistory @@*/ -static int AuthPage(cGH *cctkGH, httpRequest *request, void *data) +static int ControlPage(cGH *cctkGH, httpRequest *request, void *data) { + DECLARE_CCTK_PARAMETERS + int retval; - char message[1024]; + char message[4096]; int notauthorised; + struct httpLink *link; notauthorised = HTTP_AuthenticateBasic(request, "user"); if(!notauthorised) { - strcpy(message,"HTTP/1.0 200 Ok\r\n"); + /* Ok the person is authorised. */ + if(request->n_arguments == 0) + { + /* No arguments, so just display the page */ + strcpy(message,"HTTP/1.0 200 Ok\r\n"); - HTTP_Write(request, message, strlen(message)); + HTTP_Write(request, message, strlen(message)); - strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n"); + strcpy(message,"WWW-Authenticate: Basic realm=\"Cactus Control\"\r\n"); - HTTP_Write(request, message, strlen(message)); + HTTP_Write(request, message, strlen(message)); - strcpy(message,"Content-Type: text/html\r\n\r\n"); + strcpy(message,"Content-Type: text/html\r\n\r\n"); - HTTP_Write(request, message, strlen(message)); - - HTTP_Write(request, authorized_page, strlen(authorized_page)); + HTTP_Write(request, message, strlen(message)); + + /* Start the page */ + strcpy(message, "<HTML><HEAD><TITLE>Cactus Control and Status Page</TITLE>\n"); + strcat(message, cactus_mainheader); + strcat(message, "<center><h1>Simulation Home Page</h1></center>"); + + HTTP_Write(request, message, strlen(message)); + + if(ContentLinks) + { + strcpy(message, "<center>Quick links: "); + + for(link = ContentLinks; link; link=link->next) + { + if(link->flags & HTTP_QUICKLINK) + { + sprintf(message, + "%s[<A HREF=\"%s\">%s</a>]", + message, + link->URL, + link->name); + } + } + strcat(message,"</center>\n<br>\n"); + + HTTP_Write(request, message, strlen(message)); + } + + strcpy(message, + "<CENTER>\n" + "<FORM action=\"/control.html\" method=\"GET\">\n" + "<TABLE BORDER= 0 CELLSPACING=5 CELLPADDING=5>\n" + "<TR>\n"); + HTTP_Write(request, message, strlen(message)); + + sprintf(message, + "<TD align=left valign=center><INPUT type=\"radio\" name=\"runstate\" %s value=\"PAUSE\"> PAUSE<BR></TD>\n", + pause ? "checked" : ""); + HTTP_Write(request, message, strlen(message)); + + sprintf(message, + "<TD align=left valign=center><INPUT type=\"radio\" name=\"runstate\" %s value=\"RUN\"> RUN<BR></TD>\n", + pause ? "" : "checked"); + HTTP_Write(request, message, strlen(message)); + + strcpy(message, + "<TD align=left valign=center><INPUT type=\"radio\" name=\"runstate\" value=\"TERMINATE\"> TERMINATE<BR></TD>\n"); + HTTP_Write(request, message, strlen(message)); + + strcpy(message, + "</TR></TABLE>\n" + "<TABLE>\n" + "<TR><TD><INPUT type=\"submit\" value=\"OK\"></TD><TD> <INPUT type=\"reset\"></TD>\n" + "</TR>\n" + "</TABLE>\n" + "</FORM>\n" + "</CENTER>\n"); + + HTTP_Write(request, message, strlen(message)); + + /* Write out the footer part. */ + + retval = HTTP_Write(request, cactus_footer, strlen(cactus_footer)); + } + else + { + /* Arguments, so control simulation */ + ControlSet(cctkGH, request); + } } else { + /* Not authorised */ strcpy(message,"HTTP/1.0 401 Unauthorized\r\n"); HTTP_Write(request, message, strlen(message)); - strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n"); + strcpy(message,"WWW-Authenticate: Basic realm=\"Cactus Control\"\r\n"); HTTP_Write(request, message, strlen(message)); @@ -813,5 +1050,224 @@ static int AuthPage(cGH *cctkGH, httpRequest *request, void *data) HTTP_Write(request, notauthorized_page, strlen(notauthorized_page)); } + return 0; } + + /*@@ + @routine ControlSet + @date Sun Sep 17 14:39:50 2000 + @author Tom Goodale + @desc + Set the status of the simulation based on the controls. + @enddesc + @calls + @calledby + @history + + @endhistory + +@@*/ +static int ControlSet(cGH *cctkGH, httpRequest *request) +{ + char message[4096]; + const char *runstate; + + runstate = HTTP_ArgumentValue(request,"runstate"); + + switch(*runstate) + { + case 'T' : HTTP_SteerQueue(CCTK_THORNSTRING, "terminate", "yes"); + ControlTerminationPage(cctkGH, request); + break; + case 'P' : HTTP_SteerQueue(CCTK_THORNSTRING, "pause", "yes"); + break; + case 'R' : HTTP_SteerQueue(CCTK_THORNSTRING, "pause", "no"); + break; + default : + fprintf(stderr, "Unknown runstate '%s'\n", runstate); + } + + /* Now redirect the browser to the normal page */ + /* Status message */ + if(request->http_major_version < 1 || + (request->http_major_version == 1 && request->http_minor_version < 1)) + { + /* Older browsers don't understand 303 */ + strcpy(message,"HTTP/1.0 302 Found\r\n"); + } + else + { + strcpy(message,"HTTP/1.0 303 See Other\r\n"); + } + + sprintf(message, "%sLocation: /control.html/\r\n\r\n", message); + + HTTP_Write(request, message, strlen(message)); + + return 0; +} + + /*@@ + @routine ControlTerminationPage + @date Sun Sep 17 14:40:16 2000 + @author Tom Goodale + @desc + Page to be shown on termination of Cactus. + @enddesc + @calls + @calledby + @history + + @endhistory + +@@*/ +static int ControlTerminationPage(cGH *cctkGH, httpRequest *request) +{ + int retval; + char message[4096]; + + /* Status message */ + strcpy(message,"HTTP/1.0 200 OK\r\n"); + + HTTP_Write(request, message, strlen(message)); + + /* Content-Type */ + strcpy(message,"Content-Type: text/html\r\n\r\n"); + + HTTP_Write(request, message, strlen(message)); + + /* Start the page */ + strcpy(message,"<HTML><HEAD><TITLE>Running CACTUS Status Information : Terminated</TITLE>\n"); + + HTTP_Write(request, message, strlen(message)); + + /* Write out the main header part */ + HTTP_Write(request, cactus_mainheader, strlen(cactus_mainheader)); + + strcpy(message, "<center><h1>Simulation Home Page</h1></center>"); + + HTTP_Write(request, message, strlen(message)); + + /* Some blurb */ + strcpy(message, "<br>" + "<center><table cellspacing=5 cellpadding=5 border=0><tr><td valign=top>" + "<h3>Simulation web server:</h3>" + "<p>This browser is connected to a Cactus simulation which contains " + "a web server thorn. This thorn allows you to monitor the simulation, " + "and view and change parameters</p>" + "<p>Depending on which other thorns are active, there may be additional " + "features available, such as the viewing and downloading of output files</p>"); + + HTTP_Write(request, message, strlen(message)); + + + /* CONFIGURATION DETAILS */ + + sprintf(message, "<h3>Configuration:</h3>" + "<ul> <li>Flesh version <FONT COLOR=RED> %s" + "</FONT></li>\n" + "<li>Code compiled on <FONT COLOR=RED>" + __DATE__ "</FONT> at <FONT COLOR=RED>"__TIME__ "</font></li>\n" + "</ul>", CCTK_FullVersion()); + + HTTP_Write(request, message, strlen(message)); + + /******************************************************************************/ + + /* NEW COLUMN */ + + strcpy(message, "</td><td valign=top>"); + + HTTP_Write(request, message, strlen(message)); + + /*******************************************************************************/ + + /* CURRENT STATE OF SIMULATION */ + + if (cctkGH) + { + + sprintf(message, "<H3> Current state:</h3> " + "<ul><li>Physical time <FONT COLOR=RED> %f" + "</FONT> \n" + "<li>Iteration number <FONT COLOR=RED> %d" + "</FONT></li>\n", + cctkGH->cctk_time, + cctkGH->cctk_iteration); + + } + else + { + strcpy(message, "<li>Current cactus time is unknown</li>\n"); + } + + HTTP_Write(request, message, strlen(message)); + + strcpy(message, "<li>This Cactus run is over.</li>\n"); + + HTTP_Write(request, message, strlen(message)); + + strcpy(message, "</ul>"); + + HTTP_Write(request, message, strlen(message)); + + /* LIST COMPILED THORNS */ + + { + int i; + int nthorns; + const char **thorns; + + nthorns = CCTK_NumCompiledThorns(); + + thorns = (const char **)malloc(nthorns * sizeof(char *)); + + for(i=0; i < nthorns; i++) + { + thorns[i] = CCTK_CompiledThorn (i); + } + + /* Sort the thorns */ + qsort(thorns, nthorns, sizeof(char *), CompareStrings); + + strcpy(message, "<h3>Compiled thorns:</h3>" + "<p>This list shows all thorns compiled into the executable, " + "those thorns which have been activated in the parameter " + "file for this simulation are shown in " + "<font color=red>red</font></p>" + "<UL>"); + + for(i=0; i < nthorns; i++) + { + strcat(message, "<LI>"); + if (CCTK_IsThornActive(thorns[i])) + { + sprintf(message,"%s <FONT COLOR=red> %s </FONT>\n", message, thorns[i]); + } + else + { + strcat(message, thorns[i]); + } + } + strcat(message, "</UL>"); + + free(thorns); + } + + HTTP_Write(request, message, strlen(message)); + + + /* Finish table started by blurb */ + strcpy(message, "</td></tr></table>"); + + HTTP_Write(request, message, strlen(message)); + + /* Write out the footer part. */ + + retval = HTTP_Write(request, cactus_footer, strlen(cactus_footer)); + + /* retval = HTTP_Write(request, base_page, strlen(base_page)); */ + + return retval; +} diff --git a/src/http_Content.h b/src/http_Content.h new file mode 100644 index 0000000..c0a620e --- /dev/null +++ b/src/http_Content.h @@ -0,0 +1,30 @@ + /*@@ + @header http_Content.h + @date Sun Sep 17 14:19:23 2000 + @author Tom Goodale + @desc + Routines exported by the Content stuff. + @enddesc + @version $Header$ + @@*/ + +#ifndef __HTTP_CONTENT_H__ +#define __HTTP_CONTENT_H__ 1 + +#define HTTP_QUICKLINK 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +int HTTP_ContentLink(const char *URL, + const char *name, + const char *description, + int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* __HTTP_CONENT_H__ */ |