From 639b622d6bb364bdf813cc636607160c5926bc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ca=C3=B1as=20Vargas?= Date: Sun, 24 Jan 2016 22:08:23 +0100 Subject: [PATCH] Version 15.126 --- swad_changelog.h | 7 +- swad_string.c | 255 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 195 insertions(+), 67 deletions(-) diff --git a/swad_changelog.h b/swad_changelog.h index bb38b6c8f..412cf6c60 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -127,13 +127,18 @@ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 15.125.3 (2016-01-24)" +#define Log_PLATFORM_VERSION "SWAD 15.126 (2016-01-24)" #define CSS_FILE "swad15.121.7.css" #define JS_FILE "swad15.121.7.js" // Number of lines (includes comments but not blank lines) has been got with the following command: // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1 /* + Version 15.126: Jan 24, 2016 In any text where URL is replaced by anchor, now @nickname is also replaced to link to user's profile. (194727 lines) + 2 changes necessary in database: +UPDATE social_posts SET Content=REPLACE(Content,'@','@'); +UPDATE social_comments SET Content=REPLACE(Content,'@','@'); + Version 15.125.3: Jan 24, 2016 Fixed bug when unsharing a social note. (194610 lines) Version 15.125.2: Jan 24, 2016 Mark notifications as removed after removing a comment to a social note. (194609 lines) Version 15.125.1: Jan 24, 2016 Mark notifications as removed after removing a social note. (194603 lines) diff --git a/swad_string.c b/swad_string.c index 69f2a61c6..ce15249c0 100644 --- a/swad_string.c +++ b/swad_string.c @@ -80,46 +80,88 @@ static const char Str_CR[2] = {13,0}; /*****************************************************************************/ /* Insertion example: -In the web http://www.ugr.es/ or in http://swad.ugr.es/ you can find the info. -In the web http://www.ugr.es/ or in http://swad.ugr.es/ you can find the info. +The web site of @rms is https://stallman.org/ +The web site of @rms is https://stallman.org/ */ -#define LINK1 "" -#define LINK3 "" -#define MAX_URLS_IN_TEXT 1000 +#define ANCHOR_1_URL "" +#define ANCHOR_3 "" + +#define MAX_LINKS 1000 + #define MAX_BYTES_LIMITED_URL 1024 // Max. number of bytes of the URL shown on screen void Str_InsertLinkInURLs (char *Txt,unsigned long MaxLength,size_t MaxCharsURLOnScreen) { - unsigned long TxtLength = strlen (Txt); - unsigned LinkLength1 = strlen (LINK1); - unsigned LinkLength2 = strlen (LINK2); - unsigned LinkLength3 = strlen (LINK3); - unsigned LinkTotalLength = LinkLength1 + LinkLength2 + LinkLength3; - char *PtrSrc,*PtrDst; + extern const char *Txt_STR_LANG_ID[1+Txt_NUM_LANGUAGES]; + char ANCHOR_1_NICK[256+Ses_LENGTH_SESSION_ID]; + char ANCHOR_2_NICK[128]; + unsigned long TxtLength; + unsigned long TxtLengthWithInsertedAnchors; + unsigned Anchor1URLLength; + unsigned Anchor1NickLength; + unsigned Anchor2URLLength; + unsigned Anchor2NickLength; + unsigned Anchor3Length; + unsigned AnchorURLTotalLength; + unsigned AnchorNickTotalLength; + char *PtrSrc; + char *PtrDst; bool URLStartFound; - int NumURLs = 0,NumURL; + bool IsNickname; + int NumURLs = 0; + int NumNicks = 0; + int NumLinks = 0; + int NumLink; struct { char *PtrStart; char *PtrEnd; - size_t NumActualBytes; // Actual length of the link - } URL[MAX_URLS_IN_TEXT]; - size_t URLLengthOnScreenTotal = 0; - size_t Length,i; + size_t NumActualBytes; // Actual length of the URL/nickname + size_t AnchorsLengthUntilHere; + } Links[MAX_LINKS]; + size_t LinksTotalLength = 0; + size_t Length; + size_t i; size_t NumChars1,NumChars2; size_t NumBytesToCopy; size_t NumBytesToShow; // Length of the link displayed on screen (may be shorter than actual length) char LimitedURL[MAX_BYTES_LIMITED_URL+1]; char Ch; + /****** Initialize lengths *****/ + if (Gbl.Usrs.Me.Logged) + { + sprintf (ANCHOR_1_NICK,""); + } + else + { + sprintf (ANCHOR_1_NICK,""); + } + TxtLength = strlen (Txt); + Anchor1URLLength = strlen (ANCHOR_1_URL); + Anchor1NickLength = strlen (ANCHOR_1_NICK); + Anchor2URLLength = strlen (ANCHOR_2_URL); + Anchor2NickLength = strlen (ANCHOR_2_NICK); + Anchor3Length = strlen (ANCHOR_3); + AnchorURLTotalLength = Anchor1URLLength + Anchor2URLLength + Anchor3Length; + AnchorNickTotalLength = Anchor1NickLength + Anchor2NickLength + Anchor3Length; + /***** Find starts and ends of URLs *****/ for (PtrSrc = Txt; *PtrSrc;) + /* Check if the next char is the start of a URL */ if (tolower ((int) *PtrSrc) == (int) 'h') { URLStartFound = false; - URL[NumURLs].PtrStart = PtrSrc; + Links[NumLinks].PtrStart = PtrSrc; if (tolower ((int) *++PtrSrc) == (int) 't') // ht... { if (tolower ((int) *++PtrSrc) == (int) 't') // htt... @@ -155,7 +197,7 @@ void Str_InsertLinkInURLs (char *Txt,unsigned long MaxLength,size_t MaxCharsURLO PtrSrc += NumChars1; if ((Ch >= 0 && Ch <= 32) || Ch == '<' || Ch == '"') { - URL[NumURLs].PtrEnd = PtrSrc - NumChars1 - 1; + Links[NumLinks].PtrEnd = PtrSrc - NumChars1 - 1; break; } else if (Ch == ',' || Ch == '.' || Ch == ';' || Ch == ':' || Ch == ')' || Ch == ']' || Ch == '}') @@ -164,72 +206,134 @@ void Str_InsertLinkInURLs (char *Txt,unsigned long MaxLength,size_t MaxCharsURLO PtrSrc += NumChars2; if ((Ch >= 0 && Ch <= 32) || Ch == '<' || Ch == '"') { - URL[NumURLs].PtrEnd = PtrSrc - NumChars2 - NumChars1 - 1; + Links[NumLinks].PtrEnd = PtrSrc - NumChars2 - NumChars1 - 1; break; } } } /* Calculate length of this URL */ - URL[NumURLs].NumActualBytes = (size_t) (URL[NumURLs].PtrEnd - URL[NumURLs].PtrStart) + 1; - if (URL[NumURLs].NumActualBytes <= MaxCharsURLOnScreen) - URLLengthOnScreenTotal += URL[NumURLs].NumActualBytes; + Links[NumLinks].NumActualBytes = (size_t) (Links[NumLinks].PtrEnd - Links[NumLinks].PtrStart) + 1; + if (Links[NumLinks].NumActualBytes <= MaxCharsURLOnScreen) + LinksTotalLength += Links[NumLinks].NumActualBytes; else // If URL is too long to be displayed ==> short it { /* Make a copy of this URL */ - NumBytesToCopy = (URL[NumURLs].NumActualBytes < MAX_BYTES_LIMITED_URL) ? URL[NumURLs].NumActualBytes : - MAX_BYTES_LIMITED_URL; - strncpy (LimitedURL,URL[NumURLs].PtrStart,NumBytesToCopy); + NumBytesToCopy = (Links[NumLinks].NumActualBytes < MAX_BYTES_LIMITED_URL) ? Links[NumLinks].NumActualBytes : + MAX_BYTES_LIMITED_URL; + strncpy (LimitedURL,Links[NumLinks].PtrStart,NumBytesToCopy); LimitedURL[NumBytesToCopy] = '\0'; /* Limit the number of characters on screen of the copy, and calculate its length in bytes */ - URLLengthOnScreenTotal += Str_LimitLengthHTMLStr (LimitedURL,MaxCharsURLOnScreen); + LinksTotalLength += Str_LimitLengthHTMLStr (LimitedURL,MaxCharsURLOnScreen); } + if (NumLinks == 0) + Links[NumLinks].AnchorsLengthUntilHere = AnchorURLTotalLength; + else + Links[NumLinks].AnchorsLengthUntilHere = Links[NumLinks - 1].AnchorsLengthUntilHere + + AnchorURLTotalLength; - /* Increment number of found URLs */ - if (++NumURLs == MAX_URLS_IN_TEXT) + /* Increment number of found nicknames and links */ + NumURLs++; + NumLinks++; + if (NumLinks == MAX_LINKS) break; } } + /* Check if the next char is the start of a nickname */ + else if ((int) *PtrSrc == (int) '@') + { + Links[NumLinks].PtrStart = PtrSrc; + + /* Find nickname end */ + PtrSrc++; // Points to first character after @ + + /* A nick can have digits, letters and '_' */ + for (; + *PtrSrc; + PtrSrc++) + if (!((*PtrSrc >= 'a' && *PtrSrc <= 'z') || + (*PtrSrc >= 'A' && *PtrSrc <= 'Z') || + (*PtrSrc >= '0' && *PtrSrc <= '9') || + (*PtrSrc == '_'))) + break; + + /* Calculate length of this nickname */ + Links[NumLinks].PtrEnd = PtrSrc - 1; + Links[NumLinks].NumActualBytes = (size_t) (Links[NumLinks].PtrEnd - Links[NumLinks].PtrStart) + 1; + + /* A nick (without arroba) must have a number of characters + Nck_MIN_LENGTH_NICKNAME_WITHOUT_ARROBA <= Length <= Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA */ + Length = Links[NumLinks].NumActualBytes - 1; // Do not count the initial @ + IsNickname = (Length >= Nck_MIN_LENGTH_NICKNAME_WITHOUT_ARROBA && + Length <= Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA); + + if (IsNickname) + { + LinksTotalLength += Links[NumLinks].NumActualBytes; + if (NumLinks == 0) + Links[NumLinks].AnchorsLengthUntilHere = AnchorNickTotalLength; + else + Links[NumLinks].AnchorsLengthUntilHere = Links[NumLinks - 1].AnchorsLengthUntilHere + + AnchorNickTotalLength; + + /* Increment number of found nicknames and links */ + NumNicks++; + NumLinks++; + if (NumLinks == MAX_LINKS) + break; + } + } + /* The next char is not the start of URL or nickname */ else // Character != 'h' PtrSrc++; - if (NumURLs) // If there are one or more URLs in text + /***** If there are one or more links (URLs or nicknames) in text *****/ + if (NumLinks) { - /***** Insert links from end to start of text, only if there is enough space available in text *****/ - if (TxtLength + URLLengthOnScreenTotal + LinkTotalLength*NumURLs <= MaxLength) - for (NumURL = NumURLs - 1; - NumURL >= 0; - NumURL--) + /***** Insert links from end to start of text, + only if there is enough space available in text *****/ + TxtLengthWithInsertedAnchors = TxtLength + + LinksTotalLength + + AnchorURLTotalLength * NumURLs + + AnchorNickTotalLength * NumNicks; + if (TxtLengthWithInsertedAnchors <= MaxLength) + for (NumLink = NumLinks - 1; + NumLink >= 0; + NumLink--) { - /* Step 1: Move forward the text after the URL (it's mandatory to do the copy in reverse order to avoid overwriting source) */ + IsNickname = (*(Links[NumLink].PtrStart) == '@'); + + /* 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) */ for (i = 0, - PtrSrc = (NumURL == NumURLs - 1) ? Txt + TxtLength : - URL[NumURL + 1].PtrStart - 1, - PtrDst = PtrSrc + URLLengthOnScreenTotal + LinkTotalLength * (NumURL + 1), - Length = PtrSrc - URL[NumURL].PtrEnd; + PtrSrc = (NumLink == NumLinks - 1) ? Txt + TxtLength : + Links[NumLink + 1].PtrStart - 1, + PtrDst = PtrSrc + LinksTotalLength + Links[NumLink].AnchorsLengthUntilHere, + Length = PtrSrc - Links[NumLink].PtrEnd; i < Length; i++) *PtrDst-- = *PtrSrc--; - /* Step 2: Insert LINK3 */ - for (i=0, PtrSrc = LINK3 + LinkLength3 - 1; - i < LinkLength3; + /* Step 2: Insert ANCHOR_3 */ + for (i=0, PtrSrc = ANCHOR_3 + Anchor3Length - 1; + i < Anchor3Length; i++) *PtrDst-- = *PtrSrc--; - /* Step 3: Move forward the URL to be shown on screen */ - if (URL[NumURL].NumActualBytes <= MaxCharsURLOnScreen) + /* Step 3: Move forward the link (URL or nickname) to be shown on screen */ + if (IsNickname || + Links[NumLink].NumActualBytes <= MaxCharsURLOnScreen) { - NumBytesToShow = URL[NumURL].NumActualBytes; - PtrSrc = URL[NumURL].PtrEnd; // PtrSrc must point to end of complete URL + NumBytesToShow = Links[NumLink].NumActualBytes; + PtrSrc = Links[NumLink].PtrEnd; // PtrSrc must point to end of complete URL or nickname } else // If URL is too long to be displayed ==> short it { /* Make a copy of this URL */ - NumBytesToCopy = (URL[NumURL].NumActualBytes < MAX_BYTES_LIMITED_URL) ? URL[NumURL].NumActualBytes : - MAX_BYTES_LIMITED_URL; - strncpy (LimitedURL,URL[NumURL].PtrStart,NumBytesToCopy); + NumBytesToCopy = (Links[NumLink].NumActualBytes < MAX_BYTES_LIMITED_URL) ? Links[NumLink].NumActualBytes : + MAX_BYTES_LIMITED_URL; + strncpy (LimitedURL,Links[NumLink].PtrStart,NumBytesToCopy); LimitedURL[NumBytesToCopy] = '\0'; /* Limit the length of the copy */ @@ -243,25 +347,39 @@ void Str_InsertLinkInURLs (char *Txt,unsigned long MaxLength,size_t MaxCharsURLO i++) *PtrDst-- = *PtrSrc--; - /* Step 4: Insert LINK2 */ - for (i = 0, PtrSrc = LINK2 + LinkLength2 - 1; - i < LinkLength2; + /* Step 4: Insert ANCHOR_2_LINK or ANCHOR_2_URL */ + if (IsNickname) + for (i = 0, PtrSrc = ANCHOR_2_NICK + Anchor2NickLength - 1; + i < Anchor2NickLength; + i++) + *PtrDst-- = *PtrSrc--; + else + for (i = 0, PtrSrc = ANCHOR_2_URL + Anchor2URLLength - 1; + i < Anchor2URLLength; + i++) + *PtrDst-- = *PtrSrc--; + + /* Step 5: Insert link into directive A + (it's mandatory to do the copy in reverse order + to avoid overwriting source URL or nickname) */ + for (i = 0, PtrSrc = Links[NumLink].PtrEnd; + i < Links[NumLink].NumActualBytes; i++) *PtrDst-- = *PtrSrc--; - /* Step 5: Insert URL into directive A (it's mandatory to do the copy in reverse order to avoid overwriting source URL) */ - for (i = 0, PtrSrc = URL[NumURL].PtrEnd; - i < URL[NumURL].NumActualBytes; - i++) - *PtrDst-- = *PtrSrc--; + /* Step 6: Insert ANCHOR_1_NICK or ANCHOR_1_URL */ + if (IsNickname) + for (i = 0, PtrSrc = ANCHOR_1_NICK + Anchor1NickLength - 1; + i < Anchor1NickLength; + i++) + *PtrDst-- = *PtrSrc--; + else + for (i = 0, PtrSrc = ANCHOR_1_URL + Anchor1URLLength - 1; + i < Anchor1URLLength; + i++) + *PtrDst-- = *PtrSrc--; - /* Step 6: Insert LINK1 */ - for (i = 0, PtrSrc = LINK1 + LinkLength1 - 1; - i < LinkLength1; - i++) - *PtrDst-- = *PtrSrc--; - - URLLengthOnScreenTotal -= NumBytesToShow; + LinksTotalLength -= NumBytesToShow; } } } @@ -947,7 +1065,12 @@ void Str_ChangeFormat (Str_ChangeFrom_t ChangeFrom,Str_ChangeTo_t ChangeTo, NumPrintableCharsFromReturn++; ThereIsSpaceChar = false; break; - case 0x5C: /* "%5C" --> "\" (\) */ + case 0x40: /* "%40" --> "@" */ + strcpy (StrSpecialChar,"@"); + NumPrintableCharsFromReturn++; + ThereIsSpaceChar = false; + break; + case 0x5C: /* "%5C" --> "\" (\) */ if (ChangeTo == Str_TO_MARKDOWN) { // Escape sequence for database, two characters StrSpecialChar[0] = '\\'; // 1. An inverted bar