\n");
spliton = true;
}
void _F_button_row::drawendline(unsigned width)
{
endline_width = width;
endline = true;
}
void _F_button_row::drawleftarrow (PARAM_STRING href, bool visible)
{
arrow_left_visible = visible;
href_arrow_left = href.ptr;
}
void _F_button_row::drawrightarrow (PARAM_STRING href, bool visible)
{
arrow_right_visible = visible;
href_arrow_right = href.ptr;
}
static const char *tbhttptype[]={
"application/octet-stream", //FILE_UNKNOWN
"text/html", //FILE_TEXT
"audio/mp3", //FILE_SOUND_MP3
"audio/ogg", //FILE_SOUND_OGG
"image/jpeg", //FILE_IMAGE_JPG
"image/png", //FILE_IMAGE_PNG
"image/gig", //FILE_IMAGE_GIF
"video/mpeg", //FILE_VIDEO
"application/octet-stream", //FILE_DOC_SUDOKU
"application/octet-stream", //FILE_DOC_CHECKER
"application/octet-stream", //FILE_DOC_CHESS
"application/octet-stream", //FILE_DOC_TICTACTO
"application/octet-stream", //FILE_ZIP
"application/octet-stream", //FILE_TGZ
"application/octet-stream", //FILE_DOC_WORDPROC
"application/octet-stream", //FILE_DOC_WHITEBOARD
"video/webm", //FILE_WEBM
"image/tiff", //FILE_IMAGE_TIFF
"application/pdf", //FILE_PDF
"application/octet-stream", //FILE_DOC_CALC
"application/octet-stream", //FILE_DOC_PHOTOS
"application/octet-stream", //FILE_DOC_VIDCONF
"audio/x-wav", // FILE_SOUND_WAV
};
static_assert(sizeof(tbhttptype)/sizeof(tbhttptype[0])==FILE_TYPE_LAST,"tbhttptype is incomplete");
static void util_sendfile_common(CONNECT_INFO &con, const READINFO_receive &info, const BOB_TYPE &content, bool more, const char *handle, const char *session)
{
glocal CONNECT_INFO *con = &con;
tlmpweb_setmodified(info.modified);
tlmpweb_setexpire(time(NULL)+365*24*60*60); // Expires in one year
tlmpweb_doctype (tbhttptype[info.file_type],info.size);
htmlwrite (content.getbuffer(),content.getsize());
glocal bool more = more;
while (glocal.more){
(*glocal.con,session,handle);
htmlwrite (content.getbuffer(),content.getsize());
glocal.more = more;
//tlmp_error ("readmore success=%d msg=%s\n",success,msg);
}
}
static int util_sendfile (const char *fname)
{
int ret = -1;
FILE *fin = fopen (fname,"r");
if (fin != NULL){
struct stat64 st;
time_t mod = 0;
unsigned size = 0;
if (fstat64(fileno(fin),&st)!=-1){
size = st.st_size;
mod = st.st_mtime;
}
tlmpweb_setmodified(mod);
tlmpweb_doctype ("image/jpeg",size);
char buf[64*1024];
int n;
while ((n=fread(buf,1,sizeof(buf),fin))>0){
htmlwrite(buf,n);
}
fclose (fin);
ret = 0;
}
return ret;
}
int util_sendfile (CONNECT_INFO &con, PARAM_STRING session, PARAM_STRING filename)
{
glocal int ret = -1;
glocal CONNECT_INFO *con = &con;
glocal const char *session = session.ptr;
glocal bool is_mini_photo = strstr(filename.ptr,"/public/mini-photo.jpg")!=nullptr;
glocal bool is_photo = strstr(filename.ptr,"/public/photo.jpg")!=nullptr;
(con,session,filename,"",false);
if (success){
glocal.ret = 0;
util_sendfile_common(*glocal.con,info,content,more,handle,glocal.session);
}else if (glocal.is_mini_photo){
glocal.ret = util_sendfile("/var/www/html/no-mini-photo.jpg");
}else if (glocal.is_photo){
glocal.ret = util_sendfile("/var/www/html/no-photo.jpg");
}else{
}
return glocal.ret;
}
/*
Send a file using the public api.
The file is /username/file. We accept also username/file.
So we extract the username
*/
int util_sendpublicfile (CONNECT_INFO &con, PARAM_STRING filename)
{
glocal int ret = -1;
glocal CONNECT_INFO *con = &con;
const char *pt = filename.ptr;
if (*pt == '/') pt++;
const char *start = pt;
pt = strchr(pt,'/');
if (pt != NULL){
glocal const char *filename = pt;
glocal string username = string(start,pt-start);
(con,glocal.username,pt,0);
if (!success){
if (strcmp(glocal.filename,"/project/photo.jpg")==0){
glocal.ret = util_sendfile ("/var/www/html/no-photo.jpg");
}else if (strcmp(glocal.filename,"/project/mini-photo.jpg")==0){
glocal.ret = util_sendfile ("/var/www/html/no-mini-photo.jpg");
}
if (glocal.ret != 0) tlmp_warning ("Can't read public file %s for user %s: %s\n",glocal.filename,glocal.username.c_str(),msg);
}else{
glocal.ret = 0;
util_sendfile_common(*glocal.con,info,content,more,handle,"public");
}
}
return glocal.ret;
}
string util_flipspaces(PARAM_STRING src)
{
string ret = src.ptr;
for (auto &c:ret){
if (c == ' ') c = '_';
}
return ret;
}
/*
Extract a URL (if found) from a line.
Return true if it was a URL.
*/
static bool util_is_url(const char *txt, const char *&end,string &url)
{
bool ret = false;
const char *pt;
if (is_start_any_ofnc(txt,pt,"http://","https://")){
pt = txt;
while (*pt > ' ' && is_not_in(*pt,'"','>',',',')')) pt++;
// A URL can't end with a period
if (pt > txt && pt[-1] == '.') pt--;
url = string(txt,pt-txt);
end = pt;
ret = true;
}
return ret;
}
/*
Create a link to an internal part of the application using subformsubmit.
This works inside content being itself clickable.
*/
string util_subformsubmit (PARAM_STRING link, PARAM_STRING text)
{
return string_f("
%s\n"
,tlmpweb_curpage(),link.ptr,text.ptr);
}
/*
Format and print a
... with openitab()
*/
void util_print_span(PARAM_STRING url)
{
htmlprintf ("
%s\n",url.ptr,url.ptr);
}
/*
Format a
... with openitab()
*/
static string util_span(PARAM_STRING url)
{
return string_f("
%s",url.ptr,url.ptr);
}
/*
Format an open
... with openitab()
(no closing
*/
static string util_open_span(PARAM_STRING url)
{
return string("
";
}
void util_clickable_img (PARAM_STRING url, const char *image_width, unsigned border)
{
htmlout ("
",image_width,border,url.ptr);
htmlout ("");
}
/*
Create the HTML for a clickable image (using javascript openintab())
*/
string util_clickable_img (PARAM_STRING url, unsigned image_width)
{
string ret;
ret.reserve(500);
ret = util_open_span(url);
ret += string_f("
";
return ret;
}
/*
Remove the dot at the end of a string
*/
static void util_remove_dot(string &line, string &dot)
{
if (line.size() > 0){
dot.clear();
auto last = line.size()-1;
if (line[last] == '.'){
// The line ends with a period. It is probably not part of the ID.
line.resize(last);
dot = ".";
}
}
}
#define UTF8_ONE_BYTE_MASK 0b10000000
#define UTF8_ONE_BYTE_COUNT 0
#define UTF8_TWO_BYTE_MASK 0b11100000
#define UTF8_TWO_BYTE_COUNT 0b11000000
#define UTF8_THREE_BYTE_MASK 0b11110000
#define UTF8_THREE_BYTE_COUNT 0b11100000
#define UTF8_FOUR_BYTE_MASK 0b11111000
#define UTF8_FOUR_BYTE_COUNT 0b11110000
// This one could use a better name, I just don't know a better one (yet?)
#define UTF8_OTHER_MASK 0b00111111
static size_t utf8_codepoint_size(uint8_t text)
{
if((text & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_COUNT) {
return 1;
}
if((text & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_COUNT) {
return 2;
}
if((text & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_COUNT) {
return 3;
}
return 4;
}
/*
Copy a local link (user/project/document)
Return the pointer
*/
static const char *util_copy_locallink(const char *txt, string &doc, string &dot)
{
const char *start = txt;
while (*txt > ' ' && is_not_in(*txt,'"','\'','<','>',',','=','&')) txt++;
doc = string(start,txt-start);
util_remove_dot (doc,dot);
return txt;
}
static const char *util_name_from_path(const string &doc)
{
const char *name = strrchr(doc.c_str(),'/');
if (name == nullptr){
name = doc.c_str();
}else{
name++;
}
return name;
}
// Present a video in a span
static string util_span_video(const string &url, unsigned image_width)
{
string ret;
ret += util_open_span(url);
ret += string_f ("\n"
,image_width,url.c_str());
ret += "";
return ret;
}
// Validate that a document exist and has the proper type
static void util_validate_doc (
CONNECT_INFO &con,
const string &doc,
string &errmsg, // Will contain the error message if any
bool (*check)(FILE_TYPE file_type),
const char *filenottype) // Error message
{
FILEINFO info;
ENTRY_TYPE type = util_entrytype(con,string_f("/projects/%s",doc.c_str()),info);
if (type == ENTRY_DIR){
errmsg = string_f(MSG_U(E_ISDIR,"Tag %s: %s is a folder\n"),"_IMG",doc.c_str());
}else if (is_not_in(type,ENTRY_FILE,ENTRY_DOCUMENT)){
errmsg = string_f(MSG_U(E_NOTFOUND,"Tag %s: document %s does not exist\n"),"_IMG",doc.c_str());
}else if (!check(info.file_type)){
errmsg = string_f(filenottype,doc.c_str());
}
}
/*
Format a short message, remove the signature
Escapes < and >
Supports ? for URL
if validate is true, does some validation. Errors are reported in errmsg.
*/
string util_format_shortmsg (
PARAM_STRING msg,
unsigned nblines,
size_t size,
unsigned image_width,
bool validate,
CONNECT_INFO &con,
string &errmsg)
{
const char *txt = msg.ptr;
string ret;
ret.reserve(nblines > 0 ? nblines*100 : 1000);
unsigned pos=0;
unsigned noline=0;
if (nblines == 0) nblines=(unsigned)-1;
while (*txt != '\0' && noline < nblines){
if (*txt == '\n'){
ret += "
\n";
pos=0;
noline++;
}else{
const char *pt;
string url;
if (util_is_url(txt,pt,url)){
ret += util_span (string(txt,pt-txt));
txt = pt-1;
}else if (*txt == '<'){
if (is_start_any_ofnc(txt,pt,"
","
","","
","","
","","
","","
","")){
while (txt < pt) ret += *txt++;
txt--; // There is a txt++ at the end of the loop.
}else{
ret += "<";
}
}else if (*txt == '>'){
ret += ">";
}else if (*txt == '\t'){
unsigned nb = 4 - (pos%4);
for (unsigned i=0; i
\n";
ret += string_f ("\n"
,url.c_str());
ret += " ";
}else{
ret += "_IFRAME=";
}
txt--;
}else if (is_start_any_of(txt,pt,"_HELP=")){
txt = pt;
while (isalpha(*txt)) txt++;
string tmp(pt,txt-pt);
ret += string_f("