mirror of
https://github.com/acanas/swad-core.git
synced 2024-09-08 00:00:25 +02:00
641 lines
22 KiB
C
641 lines
22 KiB
C
// swad_autolink.c: inserting automatic links in text
|
|
|
|
/*
|
|
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ñas Vargas
|
|
|
|
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 ***********************************/
|
|
/*****************************************************************************/
|
|
|
|
#define _GNU_SOURCE // For asprintf
|
|
#include <ctype.h> // For tolower
|
|
#include <stddef.h> // For NULL
|
|
#include <stdio.h> // For asprintf
|
|
#include <stdlib.h> // For malloc and free
|
|
#include <string.h> // For string functions
|
|
|
|
#include "swad_action_list.h"
|
|
#include "swad_autolink.h"
|
|
#include "swad_config.h"
|
|
#include "swad_error.h"
|
|
#include "swad_form.h"
|
|
#include "swad_global.h"
|
|
#include "swad_nickname.h"
|
|
#include "swad_nickname_database.h"
|
|
#include "swad_photo.h"
|
|
#include "swad_string.h"
|
|
#include "swad_user.h"
|
|
#include "swad_www.h"
|
|
|
|
/*****************************************************************************/
|
|
/******************************* Private types *******************************/
|
|
/*****************************************************************************/
|
|
|
|
typedef enum
|
|
{
|
|
ALn_LINK_UNKNOWN = 0,
|
|
ALn_LINK_URL = 1,
|
|
ALn_LINK_NICK = 2,
|
|
} ALn_LinkType_t;
|
|
|
|
struct ALn_Substring
|
|
{
|
|
char *Str; // Pointer to the first char of substring
|
|
size_t Len; // Length of the substring
|
|
};
|
|
|
|
struct ALn_Link
|
|
{
|
|
ALn_LinkType_t Type; // URL or nickname?
|
|
struct ALn_Substring URLorNick; // Link text
|
|
struct ALn_Substring NickAnchor[3]; // Pointer to anchors if nick
|
|
size_t LengthAddedUpToHere; // Total length of extra HTML code
|
|
// added up to this link (included)
|
|
struct ALn_Link *Prev; // Pointer to previous link
|
|
struct ALn_Link *Next; // Pointer to next link
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/******************** Global variables from other modules ********************/
|
|
/*****************************************************************************/
|
|
|
|
extern struct Globals Gbl;
|
|
|
|
/*****************************************************************************/
|
|
/*************************** Private prototypes ******************************/
|
|
/*****************************************************************************/
|
|
|
|
static void ALn_CreateFirstLink (struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink);
|
|
static void ALn_CreateNextLink (struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink);
|
|
static void ALn_FreeLinks (struct ALn_Link *LastLink);
|
|
static ALn_LinkType_t ALn_CheckURL (char **PtrSrc,char PrevCh,
|
|
struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink,
|
|
size_t MaxCharsURLOnScreen);
|
|
static ALn_LinkType_t ALn_CheckNickname (char **PtrSrc,char PrevCh,
|
|
struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink);
|
|
static void ALn_CopySubstring (const struct ALn_Substring *PtrSrc,char **PtrDst);
|
|
|
|
/*****************************************************************************/
|
|
/**************************** Private constants ******************************/
|
|
/*****************************************************************************/
|
|
|
|
// For URLs the length of anchor is fixed, so it can be calculated once
|
|
#define ALn_URL_ANCHOR_0 "<a href=\""
|
|
#define ALn_URL_ANCHOR_1 "\" target=\"_blank\">"
|
|
#define ALn_URL_ANCHOR_2 "</a>"
|
|
|
|
#define ALn_URL_ANCHOR_0_LENGTH (sizeof (ALn_URL_ANCHOR_0) - 1)
|
|
#define ALn_URL_ANCHOR_1_LENGTH (sizeof (ALn_URL_ANCHOR_1) - 1)
|
|
#define ALn_URL_ANCHOR_2_LENGTH (sizeof (ALn_URL_ANCHOR_2) - 1)
|
|
|
|
#define ALn_URL_ANCHOR_TOTAL_LENGTH (ALn_URL_ANCHOR_0_LENGTH + ALn_URL_ANCHOR_1_LENGTH + ALn_URL_ANCHOR_2_LENGTH)
|
|
|
|
static const struct ALn_Substring URLAnchor[3] =
|
|
{
|
|
[0] = {
|
|
.Str = ALn_URL_ANCHOR_0,
|
|
.Len = ALn_URL_ANCHOR_0_LENGTH,
|
|
},
|
|
[1] = {
|
|
.Str = ALn_URL_ANCHOR_1,
|
|
.Len = ALn_URL_ANCHOR_1_LENGTH,
|
|
},
|
|
[2] = {
|
|
.Str = ALn_URL_ANCHOR_2,
|
|
.Len = ALn_URL_ANCHOR_2_LENGTH,
|
|
},
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/************** Insert automatic links in every URL or nickname **************/
|
|
/*****************************************************************************/
|
|
/*
|
|
Insertion example:
|
|
The web site of @rms is https://stallman.org/
|
|
The web site of <a href="https://openswad.org/?usr=@rms">@rms</a> is <a href="https://stallman.org/" target="_blank">https://stallman.org/</a>
|
|
*/
|
|
|
|
/*
|
|
|
|
<form action="https://localhost/swad/es" method="post">
|
|
<input type="hidden" name="ses" value="2jb9CGhIJ81_qhDyeQ6MWDFKQ5ZaA_F68tq22ZAjYww">
|
|
<input type="hidden" name="usr" value="@acanas">
|
|
<button type="submit" class="NICK_WHITE">
|
|
@acanas
|
|
</button>
|
|
</form>
|
|
|
|
*/
|
|
/*
|
|
______ ______ ______ ______
|
|
|______|<-- -->|______|<-- -->|______|<-- -->|______|<--- LastLink
|
|
|______| \/ |______| \/ |______| \/ |______|
|
|
|______| /\ |______| /\ |______| /\ |______|
|
|
|_NULL_| / ---|_Prev_| / ---|_Prev_| / ---|_Prev_|
|
|
|_Next_|-- |_Next_|-- |_Next_|-- |_NULL_|
|
|
|
|
1 Move forward the text after the link
|
|
2 Copy the 3rd part of the anchor
|
|
3 Move forward the link
|
|
4 Copy the 2nd part of the anchor
|
|
5 Copy the link into the anchor
|
|
6 Copy the 1st part of the anchor
|
|
|
|
Hi @admin, can I use https://openswad.org for free?
|
|
_______________________________
|
|
|H|i|_|@|a|d|m|i|n|,|_|c|a|n|...|
|
|
| | | | | | | | | | | | | | |
|
|
| | | | | | | | | \_\_\_\_\_\______________________________________1____
|
|
| | | \ \ \ \ \ \ \ \ \ \ \ \
|
|
| | | \_\_\_\_\_\_________________________3____ | | | | | |
|
|
| | | \ \ \ \ \ \ \ \ \ \ \ \ | | | | | |
|
|
| | | \_\_\_\_\_\_5____ | | | | | | | | | | | |
|
|
| | | \ \ \ \ \ \ | | | | | | | | | | | |
|
|
| | | 6 | | | | | | 4 | | | | | | 2 | | | | | |
|
|
v v v anchor#1 v v v v v v anchor#2 v v v v v v anchor#3 v v v v v v
|
|
___________________________________________________________________________
|
|
|H|i|_|<|_|_|_|_|@|a|d|m|i|n|_|_|_|_|>|@|a|d|m|i|n|<|_|_|_|_|>|,|_|c|a|n|...|
|
|
*/
|
|
void ALn_InsertLinks (char *Txt,unsigned long MaxLength,size_t MaxCharsURLOnScreen)
|
|
{
|
|
size_t TxtLength;
|
|
char PrevCh = '\0';
|
|
char *PtrSrc;
|
|
char *PtrDst;
|
|
struct ALn_Link *Link;
|
|
struct ALn_Link *LastLink;
|
|
size_t Length;
|
|
size_t i;
|
|
struct ALn_Substring Limited; // URL displayed on screen (may be shorter than actual length)
|
|
const struct ALn_Substring *Anchor[3];
|
|
|
|
/**************************************************************/
|
|
/***** Find starts and ends of links (URLs and nicknames) *****/
|
|
/**************************************************************/
|
|
ALn_CreateFirstLink (&Link,&LastLink);
|
|
|
|
for (PtrSrc = Txt;
|
|
*PtrSrc;)
|
|
/* Check if the next char is the start of a URL */
|
|
if ((Link->Type = ALn_CheckURL (&PtrSrc,PrevCh,
|
|
&Link,&LastLink,
|
|
MaxCharsURLOnScreen)) == ALn_LINK_UNKNOWN)
|
|
/* Check if the next char is the start of a nickname */
|
|
if ((Link->Type = ALn_CheckNickname (&PtrSrc,PrevCh,
|
|
&Link,&LastLink)) == ALn_LINK_UNKNOWN)
|
|
/* The next char is not the start of a URL or a nickname */
|
|
if (*PtrSrc) // If the end has not been reached
|
|
{
|
|
PrevCh = *PtrSrc;
|
|
PtrSrc++;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/***** If there are one or more links (URLs or nicknames) in text *****/
|
|
/**********************************************************************/
|
|
if (LastLink) // Not null ==> one or more links found
|
|
{
|
|
/***** Insert links from end to start of text,
|
|
only if there is enough space available in text *****/
|
|
TxtLength = strlen (Txt);
|
|
if (TxtLength + LastLink->LengthAddedUpToHere <= MaxLength)
|
|
{
|
|
for (Link = LastLink;
|
|
Link;
|
|
Link = Link->Prev)
|
|
{
|
|
/***** Set anchors *****/
|
|
switch (Link->Type)
|
|
{
|
|
case ALn_LINK_URL:
|
|
Anchor[0] = &URLAnchor[0];
|
|
Anchor[1] = &URLAnchor[1];
|
|
Anchor[2] = &URLAnchor[2];
|
|
break;
|
|
case ALn_LINK_NICK:
|
|
Anchor[0] = &Link->NickAnchor[0];
|
|
Anchor[1] = &Link->NickAnchor[1];
|
|
Anchor[2] = &Link->NickAnchor[2];
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
/***** Step 1: Move forward the text after the link (URL or nickname)
|
|
(it's mandatory to do the copy in reverse order
|
|
to avoid overwriting source) *****/
|
|
|
|
PtrSrc = (Link == LastLink) ? Txt + TxtLength :
|
|
Link->Next->URLorNick.Str - 1;
|
|
PtrDst = PtrSrc + Link->LengthAddedUpToHere;
|
|
Length = PtrSrc - (Link->URLorNick.Str + Link->URLorNick.Len - 1);
|
|
for (i = 0;
|
|
i < Length;
|
|
i++)
|
|
*PtrDst-- = *PtrSrc--;
|
|
|
|
/***** Step 2: Copy the third part of the anchor *****/
|
|
ALn_CopySubstring (Anchor[2],&PtrDst);
|
|
|
|
/***** Step 3: Move forward the link (URL or nickname)
|
|
to be shown on screen *****/
|
|
switch (Link->Type)
|
|
{
|
|
case ALn_LINK_URL:
|
|
if (Link->URLorNick.Len <= MaxCharsURLOnScreen)
|
|
ALn_CopySubstring (&Link->URLorNick,&PtrDst);
|
|
else
|
|
{
|
|
/* Limit the length of URL */
|
|
if ((Limited.Str = malloc (Link->URLorNick.Len + 1)) == NULL)
|
|
Err_NotEnoughMemoryExit ();
|
|
strncpy (Limited.Str,Link->URLorNick.Str,Link->URLorNick.Len);
|
|
Limited.Str[Link->URLorNick.Len] = '\0';
|
|
Limited.Len = Str_LimitLengthHTMLStr (Limited.Str,MaxCharsURLOnScreen);
|
|
ALn_CopySubstring (&Limited,&PtrDst);
|
|
free (Limited.Str);
|
|
}
|
|
break;
|
|
case ALn_LINK_NICK:
|
|
ALn_CopySubstring (&Link->URLorNick,&PtrDst);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/***** Step 4: Copy the second part of the anchor *****/
|
|
ALn_CopySubstring (Anchor[1],&PtrDst);
|
|
|
|
/***** Step 5: Copy the link into the anchor
|
|
(it's mandatory to do the copy in reverse order
|
|
to avoid overwriting source URL or nickname) *****/
|
|
ALn_CopySubstring (&Link->URLorNick,&PtrDst);
|
|
|
|
/***** Step 6: Copy the first part of the anchor *****/
|
|
ALn_CopySubstring (Anchor[0],&PtrDst);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************/
|
|
/***** Free memory for anchors *****/
|
|
/***********************************/
|
|
ALn_FreeLinks (LastLink);
|
|
}
|
|
|
|
/***************************** Create first link ******************************/
|
|
|
|
static void ALn_CreateFirstLink (struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink)
|
|
{
|
|
/***** Reset last link pointer *****/
|
|
(*LastLink) = NULL;
|
|
|
|
/***** Allocate current link *****/
|
|
if (((*Link) = malloc (sizeof (struct ALn_Link))) == NULL)
|
|
Err_NotEnoughMemoryExit ();
|
|
|
|
/***** Initialize current link *****/
|
|
(*Link)->Prev = NULL;
|
|
(*Link)->Next = NULL;
|
|
}
|
|
|
|
/***************************** Create next link ******************************/
|
|
|
|
static void ALn_CreateNextLink (struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink)
|
|
{
|
|
/***** Current link now is pointing to a correct link,
|
|
so set last link pointer to current link *****/
|
|
(*LastLink) = (*Link);
|
|
|
|
/***** Allocate next link *****/
|
|
if (((*Link)->Next = malloc (sizeof (struct ALn_Link))) == NULL)
|
|
Err_NotEnoughMemoryExit ();
|
|
|
|
/***** Initialize next link *****/
|
|
(*Link)->Next->Prev = *Link;
|
|
(*Link)->Next->Next = NULL;
|
|
|
|
/***** Change current link to just allocated link *****/
|
|
(*Link) = (*Link)->Next;
|
|
}
|
|
|
|
/***************************** Free found links ******************************/
|
|
|
|
static void ALn_FreeLinks (struct ALn_Link *LastLink)
|
|
{
|
|
struct ALn_Link *Link;
|
|
struct ALn_Link *PrevLink;
|
|
|
|
for (Link = LastLink;
|
|
Link;
|
|
Link = PrevLink)
|
|
{
|
|
PrevLink = Link->Prev;
|
|
if (Link->Type == ALn_LINK_NICK)
|
|
{
|
|
if (Link->NickAnchor[2].Str) free (Link->NickAnchor[2].Str);
|
|
if (Link->NickAnchor[1].Str) free (Link->NickAnchor[1].Str);
|
|
if (Link->NickAnchor[0].Str) free (Link->NickAnchor[0].Str);
|
|
}
|
|
free (Link);
|
|
}
|
|
}
|
|
|
|
/**************************** Check if a URL found ***************************/
|
|
|
|
static ALn_LinkType_t ALn_CheckURL (char **PtrSrc,char PrevCh,
|
|
struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink,
|
|
size_t MaxCharsURLOnScreen)
|
|
{
|
|
unsigned char Ch;
|
|
size_t NumChars1;
|
|
size_t NumChars2;
|
|
char *PtrEnd; // Pointer to the last char of URL/nickname in original text
|
|
char *Limited; // URL displayed on screen (may be shorter than actual length)
|
|
ALn_LinkType_t Type = ALn_LINK_UNKNOWN;
|
|
|
|
/***** Check if the next char is the start of a URL *****/
|
|
if (tolower ((int) *(*PtrSrc)) == (int) 'h')
|
|
if (!Str_ChIsAlphaNum (PrevCh))
|
|
{
|
|
(*Link)->URLorNick.Str = (*PtrSrc);
|
|
if (tolower ((int) *++(*PtrSrc)) == (int) 't') // ht...
|
|
{
|
|
if (tolower ((int) *++(*PtrSrc)) == (int) 't') // htt...
|
|
{
|
|
if (tolower ((int) *++(*PtrSrc)) == (int) 'p') // http...
|
|
{
|
|
(*PtrSrc)++;
|
|
if (*(*PtrSrc) == ':') // http:...
|
|
{
|
|
if (*++(*PtrSrc) == '/') // http:/...
|
|
if (*++(*PtrSrc) == '/') // http://...
|
|
Type = ALn_LINK_URL;
|
|
}
|
|
else if (tolower ((int) *(*PtrSrc)) == (int) 's') // https...
|
|
{
|
|
if (*++(*PtrSrc) == ':') // https:...
|
|
{
|
|
if (*++(*PtrSrc) == '/') // https:/...
|
|
if (*++(*PtrSrc) == '/') // https://...
|
|
Type = ALn_LINK_URL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (Type == ALn_LINK_URL)
|
|
{
|
|
/***** Find URL end *****/
|
|
(*PtrSrc)++; // Points to first character after http:// or https://
|
|
for (;;)
|
|
{
|
|
NumChars1 = Str_GetNextASCIICharFromStr ((*PtrSrc),&Ch);
|
|
(*PtrSrc) += NumChars1;
|
|
if (Ch <= 32 || Ch == '<' || Ch == '"')
|
|
{
|
|
PtrEnd = (*PtrSrc) - NumChars1 - 1;
|
|
break;
|
|
}
|
|
else if (Ch == ',' || Ch == '.' || Ch == ';' || Ch == ':' ||
|
|
Ch == ')' || Ch == ']' || Ch == '}')
|
|
{
|
|
NumChars2 = Str_GetNextASCIICharFromStr ((*PtrSrc),&Ch);
|
|
(*PtrSrc) += NumChars2;
|
|
if (Ch <= 32 || Ch == '<' || Ch == '"')
|
|
{
|
|
PtrEnd = (*PtrSrc) - NumChars2 - NumChars1 - 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** Compute number of bytes added until here *****/
|
|
(*Link)->LengthAddedUpToHere = (*Link)->Prev ? (*Link)->Prev->LengthAddedUpToHere :
|
|
0;
|
|
(*Link)->URLorNick.Len = (size_t) (PtrEnd + 1 - (*Link)->URLorNick.Str);
|
|
if ((*Link)->URLorNick.Len <= MaxCharsURLOnScreen)
|
|
(*Link)->LengthAddedUpToHere += ALn_URL_ANCHOR_TOTAL_LENGTH +
|
|
(*Link)->URLorNick.Len;
|
|
else // If URL is too long to be displayed ==> short it
|
|
{
|
|
if ((Limited = malloc ((*Link)->URLorNick.Len + 1)) == NULL)
|
|
Err_NotEnoughMemoryExit ();
|
|
strncpy (Limited,(*Link)->URLorNick.Str,(*Link)->URLorNick.Len);
|
|
Limited[(*Link)->URLorNick.Len] = '\0';
|
|
(*Link)->LengthAddedUpToHere += ALn_URL_ANCHOR_TOTAL_LENGTH +
|
|
Str_LimitLengthHTMLStr (Limited,MaxCharsURLOnScreen);
|
|
free (Limited);
|
|
}
|
|
|
|
/***** Create next link *****/
|
|
ALn_CreateNextLink (Link,LastLink);
|
|
}
|
|
}
|
|
|
|
return Type;
|
|
}
|
|
|
|
/************************* Check if a nickname found *************************/
|
|
|
|
static ALn_LinkType_t ALn_CheckNickname (char **PtrSrc,char PrevCh,
|
|
struct ALn_Link **Link,
|
|
struct ALn_Link **LastLink)
|
|
{
|
|
extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES];
|
|
static const char *ClassPhoto[PhoSha_NUM_SHAPES] =
|
|
{
|
|
[PhoSha_SHAPE_CIRCLE ] = "PHOTOC12x16",
|
|
[PhoSha_SHAPE_ELLIPSE ] = "PHOTOE12x16",
|
|
[PhoSha_SHAPE_OVAL ] = "PHOTOO12x16",
|
|
[PhoSha_SHAPE_RECTANGLE] = "PHOTOR12x16",
|
|
};
|
|
char Ch;
|
|
size_t Length;
|
|
char ParsStr[Frm_MAX_BYTES_PARAMS_STR + 1];
|
|
struct Usr_Data UsrDat;
|
|
bool ShowPhoto = false;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
char *CaptionStr;
|
|
char *ImgStr;
|
|
char NickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1];
|
|
bool NickSeemsValid;
|
|
ALn_LinkType_t Type = ALn_LINK_UNKNOWN;
|
|
|
|
/***** Check if the next char is the start of a nickname *****/
|
|
Ch = *(*PtrSrc);
|
|
if (Ch == '@') // Current is @
|
|
if (!Str_ChIsAlphaNum (PrevCh)) // Previous is not alphanumeric
|
|
if (Str_ChIsAlphaNum (*((*PtrSrc) + 1))) // Next is alphanumeric
|
|
{
|
|
(*Link)->URLorNick.Str = (*PtrSrc);
|
|
|
|
/***** Find nickname end *****/
|
|
(*PtrSrc)++; // Points to first character after @
|
|
|
|
/***** A nick can have digits, letters and '_' *****/
|
|
for (;
|
|
*(*PtrSrc);
|
|
(*PtrSrc)++)
|
|
{
|
|
Ch = *(*PtrSrc);
|
|
if (!Str_ChIsAlphaNum (Ch))
|
|
break;
|
|
}
|
|
|
|
/***** Calculate length of this nickname *****/
|
|
(*Link)->URLorNick.Len = (size_t) ((*PtrSrc) - (*Link)->URLorNick.Str);
|
|
|
|
/***** A nick (without arroba) must have a number of characters
|
|
Nck_MIN_CHARS_NICK_WITHOUT_ARROBA <= Length <= Nck_MAX_CHARS_NICK_WITHOUT_ARROBA *****/
|
|
Length = (*Link)->URLorNick.Len - 1; // Do not count the initial @
|
|
NickSeemsValid = Length >= Nck_MIN_CHARS_NICK_WITHOUT_ARROBA &&
|
|
Length <= Nck_MAX_CHARS_NICK_WITHOUT_ARROBA;
|
|
|
|
if (NickSeemsValid)
|
|
{
|
|
/***** Create data for a user *****/
|
|
Usr_UsrDataConstructor (&UsrDat);
|
|
|
|
/***** Get user's code using nickname *****/
|
|
strncpy (NickWithoutArr,(*Link)->URLorNick.Str + 1,Length);
|
|
NickWithoutArr[Length] = '\0';
|
|
if ((UsrDat.UsrCod = Nck_DB_GetUsrCodFromNickname (NickWithoutArr)) > 0)
|
|
{
|
|
Type = ALn_LINK_NICK;
|
|
Usr_GetUsrDataFromUsrCod (&UsrDat,
|
|
Usr_DONT_GET_PREFS,
|
|
Usr_DONT_GET_ROLE_IN_CRS);
|
|
}
|
|
|
|
if (Type == ALn_LINK_NICK)
|
|
{
|
|
/***** Reset anchors (checked on freeing) *****/
|
|
(*Link)->NickAnchor[0].Str =
|
|
(*Link)->NickAnchor[1].Str =
|
|
(*Link)->NickAnchor[2].Str = NULL;
|
|
|
|
/***** Store first part of anchor *****/
|
|
Frm_SetParsForm (ParsStr,ActSeeOthPubPrf,true);
|
|
if (asprintf (&(*Link)->NickAnchor[0].Str,
|
|
"<form method=\"post\" action=\"%s/%s\">"
|
|
"%s" // Parameters
|
|
"<input type=\"hidden\" name=\"usr\" value=\"",
|
|
Cfg_URL_SWAD_CGI,
|
|
Lan_STR_LANG_ID[Gbl.Prefs.Language],
|
|
ParsStr) < 0)
|
|
Err_NotEnoughMemoryExit ();
|
|
(*Link)->NickAnchor[0].Len = strlen ((*Link)->NickAnchor[0].Str);
|
|
|
|
/***** Store second part of anchor *****/
|
|
if (asprintf (&(*Link)->NickAnchor[1].Str,
|
|
"\">"
|
|
"<button type=\"submit\" class=\"NICK_%s\">",
|
|
The_GetSuffix ()) < 0)
|
|
Err_NotEnoughMemoryExit ();
|
|
(*Link)->NickAnchor[1].Len = strlen ((*Link)->NickAnchor[1].Str);
|
|
|
|
/***** Store third part of anchor *****/
|
|
ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (&UsrDat,PhotoURL);
|
|
Pho_BuildHTMLUsrPhoto (&UsrDat,ShowPhoto ? PhotoURL :
|
|
NULL,
|
|
ClassPhoto[Gbl.Prefs.PhotoShape],Pho_ZOOM,
|
|
&CaptionStr,
|
|
&ImgStr);
|
|
if (asprintf (&(*Link)->NickAnchor[2].Str,
|
|
"</button>"
|
|
"</form>"
|
|
"%s"
|
|
"%s",
|
|
CaptionStr,
|
|
ImgStr) < 0)
|
|
Err_NotEnoughMemoryExit ();
|
|
free (ImgStr);
|
|
free (CaptionStr);
|
|
(*Link)->NickAnchor[2].Len = strlen ((*Link)->NickAnchor[2].Str);
|
|
|
|
/***** Compute number of bytes added until here *****/
|
|
(*Link)->LengthAddedUpToHere = (*Link)->Prev ? (*Link)->Prev->LengthAddedUpToHere :
|
|
0;
|
|
(*Link)->LengthAddedUpToHere += (*Link)->NickAnchor[0].Len +
|
|
(*Link)->URLorNick.Len +
|
|
(*Link)->NickAnchor[1].Len +
|
|
(*Link)->NickAnchor[2].Len;
|
|
|
|
/***** Create next link *****/
|
|
ALn_CreateNextLink (Link,LastLink);
|
|
}
|
|
|
|
/***** Free memory used for user's data *****/
|
|
Usr_UsrDataDestructor (&UsrDat);
|
|
}
|
|
}
|
|
|
|
return Type;
|
|
}
|
|
|
|
/************** Copy source substring to destination, backwards **************/
|
|
|
|
static void ALn_CopySubstring (const struct ALn_Substring *Src,char **Dst)
|
|
{
|
|
char *PtrSrc; // Local pointer optimizes access to memory
|
|
char *PtrDst; // Local pointer optimizes access to memory
|
|
size_t Len = Src->Len;
|
|
/*
|
|
Example: Src->Str = "<a href=\""
|
|
Src->Len = 9
|
|
Src->Str
|
|
|
|
|
_v_________________
|
|
|<|a|_|h|r|e|f|=|"|
|
|
| | | | | | | | |
|
|
\ \ \ \ \ \ \ \ \
|
|
\ \ \ \ \ \ \ \ \
|
|
\ \ \ \ \ \ \ \ \
|
|
\ \ \ \ \ \ \ \ \
|
|
\ \ \ \ \ \ \ \ \
|
|
| | | | | | | | |
|
|
_______v_v_v_v_v_v_v_v_v_____________
|
|
|_|_|_|<|a|_|h|r|e|f|=|"|_|_|_|_|_|_|
|
|
^ ^
|
|
| |
|
|
PtrDst (*Dst)
|
|
The copy has to be done backwards to avoid overwriting the original string
|
|
*/
|
|
if (Len)
|
|
{
|
|
PtrSrc = Src->Str + Len - 1;
|
|
PtrDst = *Dst; // Make a local copy of destination pointer
|
|
for (;
|
|
Len;
|
|
Len--)
|
|
*PtrDst-- = *PtrSrc--;
|
|
*Dst = PtrDst; // Update destination pointer
|
|
}
|
|
}
|