swad-core/swad_parameter.c

1191 lines
42 KiB
C
Raw Permalink Normal View History

2014-12-01 23:55:08 +01:00
// swad_parameter.c: CGI parameters
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2024 Antonio Ca<EFBFBD>as Vargas
2014-12-01 23:55:08 +01:00
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************** Headers **********************************/
/*****************************************************************************/
#include <ctype.h> // For isprint, isspace, etc.
2019-12-29 12:39:00 +01:00
#include <stddef.h> // For NULL
2014-12-01 23:55:08 +01:00
#include <stdlib.h> // For calloc
#include <string.h> // For string functions
#include "swad_action.h"
#include "swad_action_list.h"
2014-12-01 23:55:08 +01:00
#include "swad_config.h"
#include "swad_error.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
2019-11-11 00:15:44 +01:00
#include "swad_HTML.h"
2014-12-01 23:55:08 +01:00
#include "swad_parameter.h"
#include "swad_parameter_code.h"
2014-12-01 23:55:08 +01:00
#include "swad_password.h"
#include "swad_session.h"
2019-03-26 11:53:21 +01:00
#include "swad_setting.h"
2015-01-04 15:48:24 +01:00
#include "swad_tab.h"
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*************** External global variables from others modules ***************/
/*****************************************************************************/
extern struct Globals Gbl;
2019-11-03 13:19:32 +01:00
/*****************************************************************************/
/***************************** Public constants ******************************/
/*****************************************************************************/
2019-11-04 23:33:59 +01:00
const char *Par_SEPARATOR_PARAM_MULTIPLE = "\x0a"; // Must be 1 <= character <= 31
2019-11-03 13:19:32 +01:00
/*****************************************************************************/
/**************************** Private constants ******************************/
/*****************************************************************************/
#define Par_MAX_BYTES_BOUNDARY_WITHOUT_CR_LF (128 - 1)
#define Par_MAX_BYTES_BOUNDARY_WITH_CR_LF (2 + Par_MAX_BYTES_BOUNDARY_WITHOUT_CR_LF)
/*****************************************************************************/
/************************* Private global variables **************************/
/*****************************************************************************/
static struct
{
/* Content send by the form and received by the CGI:
Act_CONTENT_NORM (if CONTENT_TYPE==text/plain)
Act_DATA (if CONTENT_TYPE==multipart/form-data) */
Act_Content_t ContentReceivedByCGI;
size_t ContentLength;
char *QueryString; // String allocated dynamically with the arguments sent to the CGI
struct Par_Param *List; // Linked list of parameters
Par_Method_t Method;
bool GetMethod; // Am I accessing using GET method?
struct
{
char StrWithoutCRLF[Par_MAX_BYTES_BOUNDARY_WITHOUT_CR_LF + 1];
char StrWithCRLF [Par_MAX_BYTES_BOUNDARY_WITH_CR_LF + 1];
size_t LengthWithoutCRLF;
size_t LengthWithCRLF;
} Boundary;
char IP[Cns_MAX_BYTES_IP + 1];
} Par_Pars =
{
.ContentReceivedByCGI = Act_NORM,
.ContentLength = 0,
.QueryString = NULL,
.List = NULL,
.Method = Par_METHOD_POST,
};
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
static inline void Par_SetContentReceivedByCGI (Act_Content_t ContentReceivedByCGI);
2016-03-31 15:03:00 +02:00
static void Par_GetBoundary (void);
static void Par_CreateListOfParsFromQueryString (void);
static void Par_CreateListOfParsFromTmpFile (void);
static int Par_ReadTmpFileUntilQuote (FILE *QueryFile);
static int Par_ReadTmpFileUntilReturn (FILE *QueryFile);
2016-03-30 14:25:04 +02:00
static bool Par_CheckIsParCanBeUsedInGETMethod (const char *ParName);
2016-03-31 19:04:13 +02:00
/*****************************************************************************/
/********************** Type of content received by CGI **********************/
/*****************************************************************************/
static inline void Par_SetContentReceivedByCGI (Act_Content_t ContentReceivedByCGI)
{
Par_Pars.ContentReceivedByCGI = ContentReceivedByCGI;
}
Act_Content_t Par_GetContentReceivedByCGI (void)
{
return Par_Pars.ContentReceivedByCGI;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*** Read all parameters passed to this CGI and store for later processing ***/
/*****************************************************************************/
2017-03-07 19:55:29 +01:00
#define Par_MAX_BYTES_METHOD (128 - 1)
#define Par_MAX_BYTES_CONTENT_TYPE (128 - 1)
2017-01-15 22:58:26 +01:00
2014-12-01 23:55:08 +01:00
bool Par_GetQueryString (void)
{
2017-03-07 19:55:29 +01:00
char Method[Par_MAX_BYTES_METHOD + 1];
char ContentType[Par_MAX_BYTES_CONTENT_TYPE + 1];
2019-11-08 01:10:32 +01:00
char UnsignedLongStr[Cns_MAX_DECIMAL_DIGITS_ULONG + 1];
2016-05-01 16:26:20 +02:00
unsigned long UnsignedLong;
2014-12-01 23:55:08 +01:00
Str_Copy (Method,getenv ("REQUEST_METHOD"),sizeof (Method) - 1);
2014-12-01 23:55:08 +01:00
if (!strcmp (Method,"GET"))
{
2016-03-30 10:50:31 +02:00
/***** GET method *****/
Par_Pars.Method = Par_METHOD_GET;
Par_SetContentReceivedByCGI (Act_NORM);
2016-03-30 10:50:31 +02:00
/* Get content length */
Par_Pars.ContentLength = strlen (getenv ("QUERY_STRING"));
2016-03-30 10:50:31 +02:00
/* Allocate memory for query string */
if ((Par_Pars.QueryString = malloc (Par_Pars.ContentLength + 1)) == NULL)
2016-03-30 10:50:31 +02:00
return false;
/* Copy query string from environment variable */
Str_Copy (Par_Pars.QueryString,getenv ("QUERY_STRING"),
Par_Pars.ContentLength);
2014-12-01 23:55:08 +01:00
}
else
{
/***** POST method *****/
Par_Pars.Method = Par_METHOD_POST;
2016-03-30 10:50:31 +02:00
/* Get content length */
if (getenv ("CONTENT_LENGTH"))
{
2017-01-17 03:10:43 +01:00
Str_Copy (UnsignedLongStr,getenv ("CONTENT_LENGTH"),
sizeof (UnsignedLongStr) - 1);
2016-05-01 16:26:20 +02:00
if (sscanf (UnsignedLongStr,"%lu",&UnsignedLong) != 1)
2016-03-30 10:50:31 +02:00
return false;
Par_Pars.ContentLength = (size_t) UnsignedLong;
2016-03-30 10:50:31 +02:00
}
else
return false;
2014-12-01 23:55:08 +01:00
/* If data are received ==> the environment variable CONTENT_TYPE will hold:
multipart/form-data; boundary=---------------------------7d13ca2e948
*/
if (getenv ("CONTENT_TYPE") == NULL)
return false;
Str_Copy (ContentType,getenv ("CONTENT_TYPE"),sizeof (ContentType) - 1);
2014-12-01 23:55:08 +01:00
if (!strncmp (ContentType,"multipart/form-data",strlen ("multipart/form-data")))
{
Par_SetContentReceivedByCGI (Act_DATA);
2016-03-31 15:03:00 +02:00
Par_GetBoundary ();
2014-12-01 23:55:08 +01:00
return Fil_ReadStdinIntoTmpFile ();
}
else if (!strncmp (ContentType,"text/xml",strlen ("text/xml")))
{
Gbl.WebService.IsWebService = true;
}
else
{
Par_SetContentReceivedByCGI (Act_NORM);
2014-12-01 23:55:08 +01:00
2016-03-30 10:50:31 +02:00
/* Allocate memory for query string */
if ((Par_Pars.QueryString = malloc (Par_Pars.ContentLength + 1)) == NULL)
2016-03-30 10:50:31 +02:00
return false;
/* Copy query string from stdin */
if (fread (Par_Pars.QueryString,sizeof (char),
Par_Pars.ContentLength,stdin) != Par_Pars.ContentLength)
2016-03-30 10:50:31 +02:00
{
Par_Pars.QueryString[0] = '\0';
2016-03-30 10:50:31 +02:00
return false;
}
Par_Pars.QueryString[Par_Pars.ContentLength] = '\0';
2014-12-01 23:55:08 +01:00
}
}
2016-03-30 14:25:04 +02:00
2014-12-01 23:55:08 +01:00
return true;
}
2016-03-31 10:11:36 +02:00
Par_Method_t Par_GetMethod (void)
{
return Par_Pars.Method;
}
2016-03-31 15:03:00 +02:00
/*****************************************************************************/
/**************************** Get boundary string ****************************/
/*****************************************************************************/
static void Par_GetBoundary (void)
{
const char *PtrToBoundary;
/*
If data are received ==> the environment variable CONTENT_TYPE will hold:
multipart/form-data; boundary=---------------------------7d13ca2e948
Gbl.Boundary.StrWithCRLF will be set to:
"\r\n-----------------------------7d13ca2e948"
I.e. 0x0D, 0x0A, '-', '-', and boundary.
*/
/***** Get pointer to boundary string *****/
PtrToBoundary = strstr (getenv ("CONTENT_TYPE"),"boundary=") + strlen ("boundary=");
/***** Check that boundary string is not too long *****/
2017-03-07 11:03:05 +01:00
if (2 + 2 + strlen (PtrToBoundary) > Par_MAX_BYTES_BOUNDARY_WITH_CR_LF)
Err_ShowErrorAndExit ("Delimiter string too long.");
2016-03-31 15:03:00 +02:00
/***** Create boundary strings *****/
snprintf (Par_Pars.Boundary.StrWithoutCRLF,sizeof (Par_Pars.Boundary.StrWithoutCRLF),
"--%s",PtrToBoundary);
snprintf (Par_Pars.Boundary.StrWithCRLF,sizeof (Par_Pars.Boundary.StrWithCRLF),
"%c%c%s",0x0D,0x0A,Par_Pars.Boundary.StrWithoutCRLF);
2016-03-31 15:03:00 +02:00
/***** Compute lengths *****/
Par_Pars.Boundary.LengthWithoutCRLF = strlen (Par_Pars.Boundary.StrWithoutCRLF);
Par_Pars.Boundary.LengthWithCRLF = 2 + Par_Pars.Boundary.LengthWithoutCRLF;
2016-03-31 15:03:00 +02:00
}
2016-03-30 17:37:56 +02:00
/*****************************************************************************/
/************************ Create list of parameters **************************/
/*****************************************************************************/
2016-03-31 02:15:17 +02:00
/*
Parameter #1 Parameter #n
+------------------+ +------------------+
List --> |Name.Start | -> |Name.Start |
+------------------+ / +------------------+
|Name.Length | | |Name.Length |
+------------------+ | +------------------+
2016-04-01 01:59:27 +02:00
|FileName.Start | | |FileName.Start |
2016-03-31 02:15:17 +02:00
+------------------+ | +------------------+
2016-04-01 01:59:27 +02:00
|FileName.Lenght | | |FileName.Lenght |
2016-03-31 02:15:17 +02:00
+------------------+ . +------------------+
|ContentType.Start | . |ContentType.Start |
+------------------+ . +------------------+
|ContentType.Lenght| | |ContentType.Lenght|
+------------------+ | +------------------+
|Value.Start | | |Value.Start |
+------------------+ | +------------------+
|Value.Lengh | | |Value.Lengh |
+------------------+ / +------------------+
| Next -------- | NULL |
+------------------+ +------------------+
2016-03-30 17:48:18 +02:00
*/
2016-03-30 17:37:56 +02:00
void Par_CreateListOfPars (void)
2016-03-30 17:37:56 +02:00
{
static void (*CreateListOfPars[Act_NUM_CONTENTS]) (void) =
{
[Act_NORM] = Par_CreateListOfParsFromQueryString,
[Act_DATA] = Par_CreateListOfParsFromTmpFile,
};
2016-03-31 10:11:36 +02:00
/***** Initialize empty list of parameters *****/
Par_Pars.List = NULL;
2016-03-31 10:11:36 +02:00
/***** Get list *****/
if (Par_Pars.ContentLength)
CreateListOfPars[Par_GetContentReceivedByCGI ()] ();
2016-03-30 17:37:56 +02:00
}
/*****************************************************************************/
/**************** Create list of parameters from query string ****************/
/*****************************************************************************/
2016-03-30 17:48:18 +02:00
static void Par_CreateListOfParsFromQueryString (void)
2016-03-30 17:37:56 +02:00
{
unsigned long CurPos; // Current position in query string
struct Par_Param *Par = NULL; // Initialized to avoid warning
struct Par_Param *NewPar;
2016-03-30 17:37:56 +02:00
/***** Check if query string is empty *****/
if (!Par_Pars.QueryString) return;
if (!Par_Pars.QueryString[0]) return;
2016-03-30 17:37:56 +02:00
/***** Go over the query string
getting start positions and lengths of parameters *****/
for (CurPos = 0;
CurPos < Par_Pars.ContentLength;
2016-03-30 17:37:56 +02:00
)
{
2016-03-31 02:15:17 +02:00
/* Allocate space for a new parameter initialized to 0 */
if ((NewPar = calloc (1,sizeof (*NewPar))) == NULL)
Err_NotEnoughMemoryExit ();
2016-03-30 17:37:56 +02:00
/* Link the previous element in list with the current element */
if (CurPos == 0)
Par_Pars.List = NewPar; // Pointer to first param
2016-03-30 17:37:56 +02:00
else
Par->Next = NewPar; // Pointer from former param to new param
2016-03-30 17:37:56 +02:00
/* Make the current element to be the just created */
Par = NewPar;
2016-03-30 17:37:56 +02:00
/* Get parameter name */
Par->Name.Start = CurPos;
Par->Name.Length = strcspn (&Par_Pars.QueryString[CurPos],"=");
CurPos += Par->Name.Length;
2016-03-30 17:37:56 +02:00
/* Get parameter value */
if (CurPos < Par_Pars.ContentLength)
if (Par_Pars.QueryString[CurPos] == '=')
2016-03-30 17:37:56 +02:00
{
CurPos++; // Skip '='
if (CurPos < Par_Pars.ContentLength)
2016-03-30 17:37:56 +02:00
{
Par->Value.Start = CurPos;
Par->Value.Length = strcspn (&Par_Pars.QueryString[CurPos],"&");
CurPos += Par->Value.Length;
if (CurPos < Par_Pars.ContentLength)
if (Par_Pars.QueryString[CurPos] == '&')
2016-03-30 17:37:56 +02:00
CurPos++; // Skip '&'
}
}
}
}
/*****************************************************************************/
/*************** Create list of parameters from temporary file ***************/
/*****************************************************************************/
2017-01-28 15:58:46 +01:00
#define Par_LENGTH_OF_STR_BEFORE_PARAM 38 // Length of "Content-Disposition: form-data; name=\""
#define Par_LENGTH_OF_STR_FILENAME 12 // Length of "; filename=\""
#define Par_LENGTH_OF_STR_CONTENT_TYPE 14 // Length of "Content-Type: "
#define Par_MAX_BYTES_STR_AUX (38 + 1) // Space to read any of the three preceding strings
2016-03-31 02:15:17 +02:00
static void Par_CreateListOfParsFromTmpFile (void)
2016-03-30 17:37:56 +02:00
{
static const char *StringBeforePar = "Content-Disposition: form-data; name=\"";
2016-03-31 02:15:17 +02:00
static const char *StringFilename = "; filename=\"";
static const char *StringContentType = "Content-Type: ";
2016-03-31 10:11:36 +02:00
unsigned long CurPos; // Current position in temporal file
struct Par_Param *Par = NULL; // Initialized to avoid warning
struct Par_Param *NewPar;
2016-03-31 02:15:17 +02:00
int Ch;
2017-01-28 15:58:46 +01:00
char StrAux[Par_MAX_BYTES_STR_AUX + 1];
FILE *QueryFile = Fil_GetQueryFile ();
2016-03-31 02:15:17 +02:00
/***** Go over the file
getting start positions and lengths of parameters *****/
if (Str_ReadFileUntilBoundaryStr (QueryFile,NULL,
Par_Pars.Boundary.StrWithoutCRLF,
Par_Pars.Boundary.LengthWithoutCRLF,
2016-04-01 03:09:45 +02:00
Fil_MAX_FILE_SIZE) == 1) // Delimiter string found
2016-03-31 02:15:17 +02:00
for (CurPos = 0;
CurPos < Par_Pars.ContentLength;
)
2016-03-31 02:15:17 +02:00
{
/***** Skip \r\n after delimiter string *****/
if (fgetc (QueryFile) != 0x0D) break; // '\r'
if (fgetc (QueryFile) != 0x0A) break; // '\n'
2016-03-31 02:15:17 +02:00
Str_GetNextStrFromFileConvertingToLower (QueryFile,StrAux,
2016-03-31 02:15:17 +02:00
Par_LENGTH_OF_STR_BEFORE_PARAM);
if (!strcasecmp (StrAux,StringBeforePar)) // Start of a parameter
2016-03-31 02:15:17 +02:00
{
/* Allocate space for a new parameter initialized to 0 */
if ((NewPar = calloc (1,sizeof (*NewPar))) == NULL)
Err_NotEnoughMemoryExit ();
2016-03-31 02:15:17 +02:00
/* Link the previous element in list with the current element */
if (CurPos == 0)
Par_Pars.List = NewPar; // Pointer to first param
2016-03-31 02:15:17 +02:00
else
Par->Next = NewPar; // Pointer from former param to new param
2016-03-31 02:15:17 +02:00
/* Make the current element to be the just created */
Par = NewPar;
2016-03-31 02:15:17 +02:00
/***** Get parameter name *****/
CurPos = (unsigned long) ftell (QueryFile); // At start of parameter name
Par->Name.Start = CurPos;
Ch = Par_ReadTmpFileUntilQuote (QueryFile);
CurPos = (unsigned long) ftell (QueryFile); // Just after quote
Par->Name.Length = CurPos - 1 - Par->Name.Start;
2016-03-31 19:04:13 +02:00
2016-03-31 02:15:17 +02:00
/* Check if last character read after parameter name is a quote */
2016-03-31 10:11:36 +02:00
if (Ch != (int) '\"') break; // '\"'
2016-03-31 02:15:17 +02:00
/* Get next char after parameter name */
Ch = fgetc (QueryFile);
2016-03-31 02:15:17 +02:00
/***** Check if filename is present *****/
if (Ch == (int) StringFilename[0])
{
Str_GetNextStrFromFileConvertingToLower (QueryFile,StrAux,
2016-03-31 02:15:17 +02:00
Par_LENGTH_OF_STR_FILENAME-1);
2017-01-28 15:58:46 +01:00
if (!strcasecmp (StrAux,StringFilename + 1)) // Start of filename
2016-03-31 02:15:17 +02:00
{
/* Get filename */
CurPos = (unsigned long) ftell (QueryFile); // At start of filename
Par->FileName.Start = CurPos;
Ch = Par_ReadTmpFileUntilQuote (QueryFile);
CurPos = (unsigned long) ftell (QueryFile); // Just after quote
Par->FileName.Length = CurPos - 1 - Par->FileName.Start;
2016-03-31 02:15:17 +02:00
/* Check if last character read after filename is a quote */
2016-03-31 10:11:36 +02:00
if (Ch != (int) '\"') break; // '\"'
2016-03-31 02:15:17 +02:00
/* Skip \r\n */
if (fgetc (QueryFile) != 0x0D) break; // '\r'
if (fgetc (QueryFile) != 0x0A) break; // '\n'
2016-03-31 02:15:17 +02:00
/* Check if Content-Type is present */
Str_GetNextStrFromFileConvertingToLower (QueryFile,StrAux,
2016-03-31 02:15:17 +02:00
Par_LENGTH_OF_STR_CONTENT_TYPE);
if (!strcasecmp (StrAux,StringContentType)) // Start of Content-Type
{
/* Get content type */
CurPos = (unsigned long) ftell (QueryFile); // At start of content type
Par->ContentType.Start = CurPos;
Ch = Par_ReadTmpFileUntilReturn (QueryFile);
CurPos = (unsigned long) ftell (QueryFile); // Just after return
Par->ContentType.Length = CurPos - 1 - Par->ContentType.Start;
2016-03-31 02:15:17 +02:00
}
}
}
/***** Now \r\n\r\n is expected just before parameter value or file content *****/
/* Check if last character read is '\r' */
2016-03-31 10:11:36 +02:00
if (Ch != 0x0D) break; // '\r'
2016-03-31 02:15:17 +02:00
/* Skip \n\r\n */
if (fgetc (QueryFile) != 0x0A) break; // '\n'
if (fgetc (QueryFile) != 0x0D) break; // '\r'
if (fgetc (QueryFile) != 0x0A) break; // '\n'
2016-03-31 02:15:17 +02:00
/***** Get parameter value or file content *****/
CurPos = (unsigned long) ftell (QueryFile); // At start of value or file content
if (Str_ReadFileUntilBoundaryStr (QueryFile,NULL,
Par_Pars.Boundary.StrWithCRLF,
Par_Pars.Boundary.LengthWithCRLF,
2016-04-01 03:09:45 +02:00
Fil_MAX_FILE_SIZE) != 1) break; // Boundary string not found
2016-03-31 02:15:17 +02:00
// Delimiter string found
Par->Value.Start = CurPos;
CurPos = (unsigned long) ftell (QueryFile); // Just after delimiter string
Par->Value.Length = CurPos - Par_Pars.Boundary.LengthWithCRLF -
Par->Value.Start;
2016-03-31 02:15:17 +02:00
}
}
}
/*****************************************************************************/
/******************** Read from file until quote '\"' ************************/
/*****************************************************************************/
// Return last char read
static int Par_ReadTmpFileUntilQuote (FILE *QueryFile)
2016-03-31 02:15:17 +02:00
{
int Ch;
/***** Read until quote if found *****/
do
Ch = fgetc (QueryFile);
2016-03-31 02:15:17 +02:00
while (Ch != EOF && Ch != (int) '\"');
return Ch;
}
/*****************************************************************************/
/*************************** Read from file until \r *************************/
/*****************************************************************************/
// Return last char read
static int Par_ReadTmpFileUntilReturn (FILE *QueryFile)
2016-03-31 02:15:17 +02:00
{
int Ch;
/***** Read until \r if found *****/
do
Ch = fgetc (QueryFile);
2016-03-31 02:15:17 +02:00
while (Ch != EOF && Ch != 0x0D); // '\r'
return Ch;
2016-03-30 17:37:56 +02:00
}
2014-12-01 23:55:08 +01:00
2016-03-30 10:50:31 +02:00
/*****************************************************************************/
/***************** Free memory allocated for query string ********************/
/*****************************************************************************/
void Par_FreePars (void)
2016-03-30 10:50:31 +02:00
{
struct Par_Param *Param;
struct Par_Param *NextParam;
2016-03-30 16:33:08 +02:00
/***** Free list of parameters *****/
for (Param = Par_Pars.List;
2016-03-30 16:33:08 +02:00
Param != NULL;
Param = NextParam)
{
NextParam = Param->Next;
2019-11-06 19:45:20 +01:00
free (Param);
2016-03-30 16:33:08 +02:00
}
/***** Free query string *****/
if (Par_Pars.QueryString)
free (Par_Pars.QueryString);
2016-03-30 10:50:31 +02:00
}
2016-03-30 17:37:56 +02:00
/*****************************************************************************/
/************************* Get the value of a parameter **********************/
/*****************************************************************************/
// Return the number of parameters found
// If ParPtr is not NULL, on return it will point to the first ocurrence in list of parameters
// ParValue can be NULL (if so, no value is copied)
2016-03-30 17:37:56 +02:00
unsigned Par_GetPar (Par_ParamType_t ParType,const char *ParName,
char *ParValue,size_t MaxBytes,
struct Par_Param **ParPtr) // NULL if not used
2016-03-30 17:37:56 +02:00
{
2019-11-03 13:19:32 +01:00
extern const char *Par_SEPARATOR_PARAM_MULTIPLE;
FILE *QueryFile = Fil_GetQueryFile ();
2016-03-30 17:37:56 +02:00
size_t BytesAlreadyCopied = 0;
unsigned i;
struct Par_Param *Par;
2016-03-30 17:37:56 +02:00
char *PtrDst;
2016-03-31 19:36:30 +02:00
unsigned NumTimes;
bool ParFound = false;
unsigned ParNameLength;
2016-04-01 01:59:27 +02:00
bool FindMoreThanOneOcurrence;
2019-02-17 01:14:55 +01:00
char ErrorTxt[256];
2016-03-31 15:03:00 +02:00
2016-03-31 19:36:30 +02:00
/***** Default values returned *****/
if (ParValue)
ParValue[0] = '\0'; // By default, the value of the parameter will be an empty string
2016-03-31 15:03:00 +02:00
/***** Only some selected parameters can be passed by GET method *****/
if (Par_GetMethod () == Par_METHOD_GET)
if (!Par_CheckIsParCanBeUsedInGETMethod (ParName))
2016-03-31 19:04:13 +02:00
return 0; // Return no-parameters-found
2016-03-31 15:03:00 +02:00
2016-03-31 19:36:30 +02:00
/***** Initializations *****/
ParNameLength = strlen (ParName);
PtrDst = ParValue;
FindMoreThanOneOcurrence = (ParType == Par_PARAM_MULTIPLE);
2016-03-31 15:03:00 +02:00
2016-03-31 19:36:30 +02:00
/***** For multiple parameters, loop for any ocurrence of the parameter
For unique parameter, find only the first ocurrence *****/
for (Par = Par_Pars.List, NumTimes = 0;
Par != NULL && (FindMoreThanOneOcurrence || NumTimes == 0);
2016-04-05 02:59:34 +02:00
)
2016-03-31 15:03:00 +02:00
/***** Find next ocurrence of parameter in list of parameters *****/
for (ParFound = false;
Par != NULL && !ParFound;
Par = Par->Next)
2016-03-31 15:03:00 +02:00
{
if (Par->Name.Length == ParNameLength)
2016-03-30 17:37:56 +02:00
{
2016-03-31 15:03:00 +02:00
// The current element in the list has the length of the searched parameter
// Check if the name of the parameter is the same
switch (Par_GetContentReceivedByCGI ())
2016-03-30 17:37:56 +02:00
{
case Act_NORM:
ParFound = !strncmp (ParName,&Par_Pars.QueryString[Par->Name.Start],
Par->Name.Length);
2016-03-31 15:03:00 +02:00
break;
case Act_DATA:
fseek (QueryFile,Par->Name.Start,SEEK_SET);
for (i = 0, ParFound = true;
i < Par->Name.Length && ParFound;
2016-03-31 15:03:00 +02:00
i++)
if (ParName[i] != (char) fgetc (QueryFile))
ParFound = false;
2016-03-31 15:03:00 +02:00
break;
2016-03-30 17:37:56 +02:00
}
if (ParFound)
2016-03-31 15:03:00 +02:00
{
2016-04-05 02:59:34 +02:00
NumTimes++;
if (NumTimes == 1) // NumTimes == 1 ==> the first ocurrence of this parameter
2016-03-31 15:03:00 +02:00
{
2016-03-31 20:09:47 +02:00
/***** Get the first ocurrence of this parameter in list *****/
if (ParPtr)
*ParPtr = Par;
2016-04-01 09:46:09 +02:00
/***** If this parameter is a file ==> do not find more ocurrences ******/
if (Par->FileName.Start != 0) // It's a file
2016-04-01 09:46:09 +02:00
FindMoreThanOneOcurrence = false;
2016-03-31 20:09:47 +02:00
}
2016-04-05 02:59:34 +02:00
else // NumTimes > 1 ==> not the first ocurrence of this parameter
2016-03-31 20:09:47 +02:00
{
/***** Add separator when param multiple *****/
2016-03-31 15:03:00 +02:00
/* Check if there is space to copy separator */
if (BytesAlreadyCopied + 1 > MaxBytes)
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorTxt,sizeof (ErrorTxt),
2018-10-16 21:56:01 +02:00
"Multiple parameter <strong>%s</strong> too large,"
" it exceed the maximum allowed size (%lu bytes).",
ParName,(unsigned long) MaxBytes);
Err_ShowErrorAndExit (ErrorTxt);
2016-03-31 15:03:00 +02:00
}
/* Copy separator */
2016-04-01 09:46:09 +02:00
if (PtrDst)
2019-11-03 13:19:32 +01:00
*PtrDst++ = Par_SEPARATOR_PARAM_MULTIPLE[0]; // Separator in the destination string
2016-03-31 15:03:00 +02:00
BytesAlreadyCopied++;
}
/***** Copy parameter value *****/
if (Par->Value.Length)
2016-03-31 15:03:00 +02:00
{
/* Check if there is space to copy the parameter value */
if (BytesAlreadyCopied + Par->Value.Length > MaxBytes)
2016-03-31 15:03:00 +02:00
{
2019-02-17 01:14:55 +01:00
snprintf (ErrorTxt,sizeof (ErrorTxt),
2018-10-16 21:56:01 +02:00
"Parameter <strong>%s</strong> too large,"
" it exceed the maximum allowed size (%lu bytes).",
ParName,(unsigned long) MaxBytes);
Err_ShowErrorAndExit (ErrorTxt);
2016-03-31 15:03:00 +02:00
}
/* Copy parameter value */
switch (Par_GetContentReceivedByCGI ())
2016-03-31 15:03:00 +02:00
{
case Act_NORM:
2016-04-01 09:46:09 +02:00
if (PtrDst)
strncpy (PtrDst,&Par_Pars.QueryString[Par->Value.Start],
Par->Value.Length);
2016-03-31 15:03:00 +02:00
break;
case Act_DATA:
if (Par->FileName.Start == 0 && // Copy into destination only if it's not a file
2016-04-01 09:46:09 +02:00
PtrDst)
{
fseek (QueryFile,Par->Value.Start,SEEK_SET);
if (fread (PtrDst,sizeof (char),Par->Value.Length,QueryFile) !=
Par->Value.Length)
Err_ShowErrorAndExit ("Error while getting value of parameter.");
2016-04-01 09:46:09 +02:00
}
2016-03-31 15:03:00 +02:00
break;
}
BytesAlreadyCopied += Par->Value.Length;
2016-04-01 09:46:09 +02:00
if (PtrDst)
PtrDst += Par->Value.Length;
2016-03-31 15:03:00 +02:00
}
}
}
}
2016-03-30 17:37:56 +02:00
2016-04-01 09:46:09 +02:00
if (PtrDst)
*PtrDst = '\0'; // Add the final NULL
2016-03-31 15:03:00 +02:00
2016-03-30 17:37:56 +02:00
return NumTimes;
}
2016-03-31 19:04:13 +02:00
/*****************************************************************************/
/*************** Check if parameter can be used in GET method ****************/
/*****************************************************************************/
static bool Par_CheckIsParCanBeUsedInGETMethod (const char *ParName)
2016-03-31 19:04:13 +02:00
{
#define NUM_VALID_PARAMS 10
static const char *ValidParsInGETMethod[NUM_VALID_PARAMS] =
2016-03-31 19:04:13 +02:00
{
"cty", // To enter directly to a country
"ins", // To enter directly to an institution
"ctr", // To enter directly to a center
2016-03-31 19:04:13 +02:00
"deg", // To enter directly to a degree
"crs", // To enter directly to a course
2016-12-03 23:48:03 +01:00
"usr", // To enter directly to a user's profile
2016-12-04 03:50:25 +01:00
"agd", // To view user's public agenda
2016-03-31 19:04:13 +02:00
"act", // To execute directly an action (allowed only for fully public actions)
"ses", // To use an open session when redirecting from one language to another
"key", // To verify an email address
};
unsigned i;
for (i = 0;
i < NUM_VALID_PARAMS;
i++)
if (!strcmp (ParName,ValidParsInGETMethod[i]))
2016-03-31 19:04:13 +02:00
return true;
return false;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/****************** Get the parameters sent to this CGI **********************/
/*****************************************************************************/
void Par_GetMainPars (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Par_CodeStr[Par_NUM_PAR_COD];
2017-01-30 01:08:25 +01:00
long ActCod;
char Nick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2014-12-01 23:55:08 +01:00
// First of all, get action, and session identifier.
// So, if other parameters have been stored in the database, there will be no problems to get them.
/***** Get action to perform *****/
if (Gbl.WebService.IsWebService)
{
2019-02-14 19:22:38 +01:00
Gbl.Action.Act = Gbl.Action.Original = ActWebSvc;
2015-01-04 15:48:24 +01:00
Tab_SetCurrentTab ();
2014-12-01 23:55:08 +01:00
return;
}
2016-10-09 22:22:47 +02:00
/***** Set default action *****/
2019-02-14 19:22:38 +01:00
Gbl.Action.Act = Gbl.Action.Original = ActUnk;
2016-01-14 01:39:02 +01:00
/***** Get another user's nickname, if exists
2016-01-26 09:47:35 +01:00
(this nickname is used to go to another user's profile,
2016-01-14 01:39:02 +01:00
not to get the logged user) *****/
if (Par_GetParText ("usr",Nick,sizeof (Nick) - 1))
2016-12-04 03:50:25 +01:00
{
if (Nick[0])
2016-01-26 09:47:35 +01:00
{
2016-12-05 13:26:12 +01:00
/* Set another user's nickname */
Str_RemoveLeadingArrobas (Nick);
Str_Copy (Gbl.Usrs.Other.UsrDat.Nickname,Nick, // Leading arrobas already removed
sizeof (Gbl.Usrs.Other.UsrDat.Nickname) - 1);
2016-12-05 13:26:12 +01:00
2016-01-26 09:47:35 +01:00
// This user's code is used to go to public profile
// and to refresh old publishings in user's timeline
// If user does not exist ==> UsrCod = -1
2016-12-05 13:26:12 +01:00
Gbl.Usrs.Other.UsrDat.UsrCod = Nck_GetUsrCodFromNickname (Gbl.Usrs.Other.UsrDat.Nickname);
2019-02-14 19:22:38 +01:00
Gbl.Action.Act = Gbl.Action.Original = ActSeeOthPubPrf; // Set default action if no other is specified
2016-01-26 09:47:35 +01:00
}
2016-12-04 03:50:25 +01:00
}
else if (Par_GetParText ("agd",Nick,sizeof (Nick) - 1))
2016-12-04 03:50:25 +01:00
{
if (Nick[0])
2016-12-04 03:50:25 +01:00
{
2016-12-05 13:26:12 +01:00
/* Set another user's nickname */
Str_RemoveLeadingArrobas (Nick);
Str_Copy (Gbl.Usrs.Other.UsrDat.Nickname,Nick, // Leading arrobas already removed
sizeof (Gbl.Usrs.Other.UsrDat.Nickname) - 1);
2016-12-05 13:26:12 +01:00
2016-12-04 03:50:25 +01:00
// This user's code is used to go to public agenda
// If user does not exist ==> UsrCod = -1
2016-12-05 13:26:12 +01:00
Gbl.Usrs.Other.UsrDat.UsrCod = Nck_GetUsrCodFromNickname (Gbl.Usrs.Other.UsrDat.Nickname);
2019-02-14 19:22:38 +01:00
Gbl.Action.Act = Gbl.Action.Original = ActFrmLogInUsrAgd; // Set default action if no other is specified
2016-12-04 03:50:25 +01:00
}
}
2016-01-14 01:39:02 +01:00
/***** Get action to perform *****/
ActCod = Par_GetParLong ("act");
if (ActCod >= 0 && ActCod <= ActLst_MAX_ACTION_COD)
Gbl.Action.Act = Gbl.Action.Original = Act_GetActionFromActCod (ActCod);
2016-12-04 03:50:25 +01:00
/***** Some preliminary adjusts depending on action *****/
2019-04-19 13:11:54 +02:00
switch (Act_GetBrowserTab (Gbl.Action.Act))
2017-02-05 22:23:41 +01:00
{
case Act_AJA:
2019-04-19 13:11:54 +02:00
Gbl.Action.UsesAJAX = true;
Gbl.Action.IsAJAXAutoRefresh = false;
break;
case Act_REF:
2019-04-19 13:11:54 +02:00
Gbl.Action.UsesAJAX = true;
Gbl.Action.IsAJAXAutoRefresh = true;
break;
default:
Gbl.Action.UsesAJAX = false;
Gbl.Action.IsAJAXAutoRefresh = false;
break;
2017-02-05 22:23:41 +01:00
}
2014-12-01 23:55:08 +01:00
/***** Get session identifier, if exists *****/
Par_GetParText ("ses",Gbl.Session.Id,Cns_BYTES_SESSION_ID);
2014-12-01 23:55:08 +01:00
if (Gbl.Session.Id[0])
{
/***** Get user's code, password, current degree and current course from stored session *****/
if (Ses_GetSessionData ())
Gbl.Session.IsOpen = true;
else
{
Gbl.Session.HasBeenDisconnected = true;
Gbl.Session.Id[0] = '\0';
}
}
2015-03-09 00:16:18 +01:00
else
{
// Try old parameter "IdSes" (allowed for compatibility, to be removed soon)
Par_GetParText ("IdSes",Gbl.Session.Id,Cns_BYTES_SESSION_ID);
2015-03-09 00:16:18 +01:00
if (Gbl.Session.Id[0])
{
/***** Get user's code, password, current degree and current course from stored session *****/
if (Ses_GetSessionData ())
Gbl.Session.IsOpen = true;
else
{
Gbl.Session.HasBeenDisconnected = true;
Gbl.Session.Id[0] = '\0';
}
}
}
2014-12-01 23:55:08 +01:00
/***** Get user password and login *****/
2016-01-17 15:10:54 +01:00
switch (Gbl.Action.Act)
2014-12-01 23:55:08 +01:00
{
2016-12-05 13:26:12 +01:00
case ActLogIn:
2016-12-04 04:22:36 +01:00
case ActFrmLogInUsrAgd:
case ActLogInUsrAgd: // This action is necessary here when log in fails
Pwd_GetParUsrPwdLogin ();
2018-10-04 21:57:25 +02:00
/* falls through */
/* no break */
2014-12-01 23:55:08 +01:00
case ActReqSndNewPwd:
case ActSndNewPwd:
Usr_GetParUsrIdLogin ();
2014-12-01 23:55:08 +01:00
break;
default:
break;
2014-12-01 23:55:08 +01:00
}
2019-03-26 11:53:21 +01:00
/***** Try to get settings changed from current IP *****/
Set_GetSettingsFromIP ();
2014-12-01 23:55:08 +01:00
/***** Get country if exists (from menu) *****/
Par_GetParText (Par_CodeStr[ParCod_Cty],LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (LongStr[0]) // Parameter available
2014-12-01 23:55:08 +01:00
{
Gbl.Hierarchy.Node[Hie_CTY].HieCod = Str_ConvertStrCodToLongCod (LongStr);
Gbl.Hierarchy.Node[Hie_INS].HieCod =
Gbl.Hierarchy.Node[Hie_CTR].HieCod =
Gbl.Hierarchy.Node[Hie_DEG].HieCod =
Gbl.Hierarchy.Node[Hie_CRS].HieCod = -1L;
2014-12-01 23:55:08 +01:00
}
/***** Get institution if exists (from menu) *****/
Par_GetParText (Par_CodeStr[ParCod_Ins],LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (LongStr[0]) // Parameter available
2014-12-01 23:55:08 +01:00
{
Gbl.Hierarchy.Node[Hie_INS].HieCod = Str_ConvertStrCodToLongCod (LongStr);
Gbl.Hierarchy.Node[Hie_CTR].HieCod =
Gbl.Hierarchy.Node[Hie_DEG].HieCod =
Gbl.Hierarchy.Node[Hie_CRS].HieCod = -1L;
2014-12-01 23:55:08 +01:00
}
/***** Get center if exists (from menu) *****/
Par_GetParText (Par_CodeStr[ParCod_Ctr],LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (LongStr[0]) // Parameter available
2014-12-01 23:55:08 +01:00
{
Gbl.Hierarchy.Node[Hie_CTR].HieCod = Str_ConvertStrCodToLongCod (LongStr);
Gbl.Hierarchy.Node[Hie_DEG].HieCod =
Gbl.Hierarchy.Node[Hie_CRS].HieCod = -1L;
2014-12-01 23:55:08 +01:00
}
/***** Get numerical degree code if exists (from menu) *****/
Par_GetParText (Par_CodeStr[ParCod_Deg],LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (LongStr[0]) // Parameter available
2014-12-01 23:55:08 +01:00
{
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Str_ConvertStrCodToLongCod (LongStr);
Gbl.Hierarchy.Node[Hie_CRS].HieCod = -1L; // Reset possible course from session
2014-12-01 23:55:08 +01:00
}
/***** Get numerical course code if exists (from menu) *****/
Par_GetParText (Par_CodeStr[ParCod_Crs],LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (LongStr[0]) // Parameter available
Gbl.Hierarchy.Node[Hie_CRS].HieCod = Str_ConvertStrCodToLongCod (LongStr); // Overwrite CrsCod from session
2014-12-01 23:55:08 +01:00
/***** Get tab to activate *****/
2016-01-17 15:10:54 +01:00
Gbl.Action.Tab = TabUnk;
if (Gbl.Action.Act == ActMnu)
2014-12-01 23:55:08 +01:00
{
2017-01-29 21:41:08 +01:00
Gbl.Action.Tab = (Tab_Tab_t)
Par_GetParUnsignedLong ("NxtTab",
(unsigned long) TabUnk,
Tab_NUM_TABS - 1,
(unsigned long) TabUnk);
2017-01-29 12:42:19 +01:00
Tab_DisableIncompatibleTabs ();
2014-12-01 23:55:08 +01:00
}
else // Set tab depending on current action
2015-01-04 15:48:24 +01:00
Tab_SetCurrentTab ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******* Get the value of a single parameter and change format to text *******/
/*****************************************************************************/
// Return the number of parameters found
unsigned Par_GetParText (const char *ParName,char *ParValue,size_t MaxBytes)
2014-12-01 23:55:08 +01:00
{
return Par_GetParAndChangeFormat (ParName,ParValue,MaxBytes,
Str_TO_TEXT,
Str_REMOVE_SPACES);
2014-12-01 23:55:08 +01:00
}
2017-01-29 12:42:19 +01:00
/*****************************************************************************/
/****************** Get the unsigned value of a parameter ********************/
/*****************************************************************************/
unsigned long Par_GetParUnsignedLong (const char *ParName,
unsigned long Min,
unsigned long Max,
unsigned long Default)
2017-01-29 12:42:19 +01:00
{
2019-11-08 01:10:32 +01:00
char UnsignedLongStr[Cns_MAX_DECIMAL_DIGITS_ULONG + 1];
2017-01-29 21:41:08 +01:00
unsigned long UnsignedLongNum;
2017-01-29 12:42:19 +01:00
/***** Get parameter with unsigned number *****/
Par_GetParText (ParName,UnsignedLongStr,Cns_MAX_DECIMAL_DIGITS_ULONG);
2017-01-29 21:41:08 +01:00
if (sscanf (UnsignedLongStr,"%lu",&UnsignedLongNum) == 1)
if (UnsignedLongNum >= Min && UnsignedLongNum <= Max)
return UnsignedLongNum;
2017-01-29 12:42:19 +01:00
return Default;
}
2017-01-28 20:32:50 +01:00
/*****************************************************************************/
/******************** Get the long value of a parameter **********************/
/*****************************************************************************/
long Par_GetParLong (const char *ParName)
2017-01-28 20:32:50 +01:00
{
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2017-01-28 20:32:50 +01:00
/***** Get parameter with long number *****/
Par_GetParText (ParName,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2017-01-28 20:32:50 +01:00
return Str_ConvertStrCodToLongCod (LongStr);
}
/*****************************************************************************/
/************************ Get a boolean Y/N parameter ************************/
2017-01-28 20:32:50 +01:00
/*****************************************************************************/
bool Par_GetParBool (const char *ParName)
2017-01-28 20:32:50 +01:00
{
char YN[1 + 1];
/***** Get parameter "Y"/"N" and convert to boolean *****/
Par_GetParText (ParName,YN,1);
2017-01-28 20:32:50 +01:00
return (Str_ConvertToUpperLetter (YN[0]) == 'Y');
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*** Get value of a single parameter and change format to not rigorous HTML **/
/*****************************************************************************/
// Return the number of parameters found
unsigned Par_GetParHTML (const char *ParName,char *ParValue,size_t MaxBytes)
2014-12-01 23:55:08 +01:00
{
return Par_GetParAndChangeFormat (ParName,ParValue,MaxBytes,
Str_TO_HTML,Str_REMOVE_SPACES);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****** Get the value of a multiple parameter and change format to text ******/
/*****************************************************************************/
// Return the number of parameters found
unsigned Par_GetParMultiToText (const char *ParName,char *ParValue,size_t MaxBytes)
2014-12-01 23:55:08 +01:00
{
unsigned NumTimes = Par_GetPar (Par_PARAM_MULTIPLE,ParName,
ParValue,MaxBytes,NULL);
2017-01-17 14:24:54 +01:00
2014-12-01 23:55:08 +01:00
Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT,
ParValue,MaxBytes,Str_REMOVE_SPACES);
2014-12-01 23:55:08 +01:00
return NumTimes;
}
/*****************************************************************************/
/*********** Get the value of a single parameter and change format ***********/
/*****************************************************************************/
// Return the number of parameters found
unsigned Par_GetParAndChangeFormat (const char *ParName,char *ParValue,size_t MaxBytes,
Str_ChangeTo_t ChangeTo,
Str_RemoveSpaces_t RemoveLeadingAndTrailingSpaces)
2014-12-01 23:55:08 +01:00
{
unsigned NumTimes = Par_GetPar (Par_PARAM_SINGLE,ParName,
ParValue,MaxBytes,NULL);
2016-04-07 23:35:47 +02:00
2014-12-01 23:55:08 +01:00
Str_ChangeFormat (Str_FROM_FORM,ChangeTo,
ParValue,MaxBytes,RemoveLeadingAndTrailingSpaces);
2014-12-01 23:55:08 +01:00
return NumTimes;
}
/*****************************************************************************/
/***** Search in the string StrSrc the next string until find separator ******/
/*****************************************************************************/
// Modifies *StrSrc
// When StrDst is NULL, nothing is stored
// Return true if characters found
bool Par_GetNextStrUntilSeparParMult (const char **StrSrc,char *StrDst,size_t LongMax)
2014-12-01 23:55:08 +01:00
{
size_t i = 0;
unsigned char Ch; // Must be unsigned to work with characters > 127
bool CharsFound = false;
do
if ((Ch = (unsigned char) **StrSrc))
(*StrSrc)++;
2019-09-24 01:41:51 +02:00
while (Ch && Ch < 32); // Skip special characters
// (the separator will be a special character
// less than 32)
2014-12-01 23:55:08 +01:00
2019-09-24 01:41:51 +02:00
while (Ch >= 32) // Until special character or end
2014-12-01 23:55:08 +01:00
{
CharsFound = true;
if (i < LongMax)
if (StrDst)
StrDst[i++] = (char) Ch;
if ((Ch = (unsigned char) **StrSrc))
(*StrSrc)++;
}
if (StrDst)
StrDst[i] = '\0';
return CharsFound;
}
/*****************************************************************************/
2020-05-12 02:45:03 +02:00
/***** Search in the string StrSrc the next string until find separator ******/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-05-12 02:45:03 +02:00
// Modifies *StrSrc
// When StrDst is NULL, nothing is stored
// Return true if characters found
2014-12-01 23:55:08 +01:00
2020-05-12 02:45:03 +02:00
bool Par_GetNextStrUntilComma (const char **StrSrc,char *StrDst,size_t LongMax)
2014-12-01 23:55:08 +01:00
{
2020-05-12 02:45:03 +02:00
size_t i = 0;
unsigned char Ch; // Must be unsigned to work with characters > 127
bool CharsFound = false;
do
if ((Ch = (unsigned char) **StrSrc))
(*StrSrc)++;
while (Ch == ','); // Skip commas
while (Ch && Ch != ',') // Until special character or end
{
CharsFound = true;
if (i < LongMax)
if (StrDst)
StrDst[i++] = (char) Ch;
if ((Ch = (unsigned char) **StrSrc))
(*StrSrc)++;
}
if (StrDst)
StrDst[i] = '\0';
return CharsFound;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******** Replace each comma by the separator of multiple parameters *********/
/*****************************************************************************/
2020-05-12 02:45:03 +02:00
void Par_ReplaceSeparatorMultipleByComma (char *Str)
2014-12-01 23:55:08 +01:00
{
for (;
*Str;
Str++)
2020-05-12 02:45:03 +02:00
if ((unsigned char) *Str < 32)
*Str = ',';
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************** Put an unsigned hidden parameter *********************/
/*****************************************************************************/
void Par_PutParUnsigned (const char *Id,const char *ParName,unsigned ParValue)
2014-12-01 23:55:08 +01:00
{
2019-11-11 00:15:44 +01:00
HTM_Txt ("<input type=\"hidden\"");
2019-11-03 13:19:32 +01:00
if (Id)
if (Id[0])
2019-11-11 00:15:44 +01:00
HTM_TxtF (" id=\"%s\"",Id);
HTM_TxtF (" name=\"%s\" value=\"%u\" />",ParName,ParValue);
2019-11-03 13:19:32 +01:00
}
void Par_PutParUnsignedDisabled (const char *Id,const char *ParName,unsigned ParValue)
2019-11-03 13:19:32 +01:00
{
2019-11-11 00:15:44 +01:00
HTM_Txt ("<input type=\"hidden\"");
2019-11-03 13:19:32 +01:00
if (Id)
if (Id[0])
2019-11-11 00:15:44 +01:00
HTM_TxtF (" id=\"%s\"",Id);
HTM_TxtF (" name=\"%s\" value=\"%u\" disabled=\"disabled\" />",
ParName,ParValue);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************** Put the value of a code parameter **********************/
/*****************************************************************************/
void ParCod_PutPar (ParCod_Param_t ParCod,long Cod)
{
extern const char *Par_CodeStr[Par_NUM_PAR_COD];
if (ParCod != ParCod_None && Cod >= 0)
// <0 => not specified => don't write parameter
// 0 => another country, institution, centre...
// >0 => a given country, institution, centre...
Par_PutParLong (NULL,Par_CodeStr[ParCod],Cod);
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************************* Put a long hidden parameter ***********************/
/*****************************************************************************/
void Par_PutParLong (const char *Id,const char *ParName,long ParValue)
2014-12-01 23:55:08 +01:00
{
2019-11-11 00:15:44 +01:00
HTM_Txt ("<input type=\"hidden\"");
2019-11-03 13:19:32 +01:00
if (Id)
if (Id[0])
2019-11-11 00:15:44 +01:00
HTM_TxtF (" id=\"%s\"",Id);
HTM_TxtF (" name=\"%s\" value=\"%ld\" />",ParName,ParValue);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************* Put a char hidden parameter ***********************/
/*****************************************************************************/
void Par_PutParChar (const char *ParName,char ParValue)
2014-12-01 23:55:08 +01:00
{
2019-11-11 00:15:44 +01:00
HTM_TxtF ("<input type=\"hidden\" name=\"%s\" value=\"%c\" />",
ParName,ParValue);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************ Put a string hidden parameter **********************/
/*****************************************************************************/
void Par_PutParString (const char *Id,const char *ParName,const char *ParValue)
2014-12-01 23:55:08 +01:00
{
2019-11-11 00:15:44 +01:00
HTM_Txt ("<input type=\"hidden\"");
2019-11-03 13:19:32 +01:00
if (Id)
if (Id[0])
2019-11-11 00:15:44 +01:00
HTM_TxtF (" id=\"%s\"",Id);
2020-03-26 21:39:44 +01:00
HTM_TxtF (" name=\"%s\" value=\"%s\" />",
ParName,ParValue ? ParValue :
"");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********* Put a hidden parameter with the type of order in listing **********/
/*****************************************************************************/
void Par_PutParOrder (unsigned SelectedOrder)
{
Par_PutParUnsigned (NULL,"Order",SelectedOrder);
}
/*****************************************************************************/
/****************************** Set/Get current IP ***************************/
/*****************************************************************************/
/*
CGI Environment Variables:
REMOTE_ADDR
The IP address of the remote host making the request.
*/
void Par_SetIP (void)
{
if (getenv ("REMOTE_ADDR"))
Str_Copy (Par_Pars.IP,getenv ("REMOTE_ADDR"),sizeof (Par_Pars.IP) - 1);
else
Par_Pars.IP[0] = '\0';
}
const char *Par_GetIP (void)
{
return Par_Pars.IP;
}