1 # ===================================================================== 2 # groupPageMap.awk: RPC I/O function for rpclib/groupPageMap. 3 # 4 # Copyright (c) 2007-2011 Carlo Strozzi 5 # 6 # This program is free software; you can redistribute it and/or modify 7 # it under the terms of the GNU General Public License as published by 8 # the Free Software Foundation; version 2 dated June, 1991. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program; if not, write to the Free Software 17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 # 19 # ===================================================================== 20 21 # ===================================================================== 22 # void _userproc(int mode) 23 # ===================================================================== 24 25 function _userproc(mode, value,outfile,i,j,n,blkno,tmp1,buy,\ 26 curr,first,last,tot,url,a,b,w,fmt,\ 27 fmt1,fmt2,fmt3,stem,tmp,blksize,e,\ 28 f,f1,f2,f3,fmt4,f4,c,d,tmp2,tmp3,r,\ 29 oldcat){ 30 31 if (mode == _O_REQUEST) { # request. 32 33 # target group 34 value = _request("1",1) 35 36 # group must not be null and it may not contain the 37 # unescaped ``.'' character. 38 39 if (value != _NULL && value !~ /\./) { 40 _rcset("cgi.group",unixify(value)) 41 _rcset("cgi.group.literal",value) 42 } 43 44 # Optional target meta-category within group, provided it 45 # is at least 3 characters in length. If it is shorter 46 # (but not null), then it is set to a bogus value. 47 48 if ((value=_request("2",1)) != _NULL) { 49 _rcset("cgi.subcat.literal",value) 50 51 # I cannot use the length() function to assess whether the 52 # supplied pattern is too short, because I need to ensure 53 # that the search string contains at least three *contiguous* 54 # alphanumeric characters. This is to account for the additional 55 # fuzziness that will be introduced by the underlying shell 56 # script when fuzzy-matching is requested, which will result in 57 # any sequences non-alphanumeric characters to be turned into 58 # the ".+" wildcard. Note that the "too.short" keyword contains 59 # one dot, to make sure it does not collide with an existing 60 # subcat named "tooshort". 61 62 if ((value=unixify(value,1)) !~ /[a-z0-9][a-z0-9][a-z0-9]/) 63 value = "too.short" 64 _rcset("cgi.subcat",value) 65 } 66 67 # Optional starting page no. for paged results. 68 if ((value=_request("3",1)/1) > 0) _rcset("cgi.paging",value) 69 70 # Optional full-text search mode, with trailing fuzziness 71 # between 1 and 3 . 72 if ((value=_request("4",1)) ~ /^[fF][1-3]?$/) 73 _rcset("cgi.scope",value) 74 75 # Optional randomized result mode. 76 if ((value=_request("5",1)) == "r") _rcset("cgi.random",value) 77 78 # Optional no. of map entries per row. 79 value =_request("6",1) 80 if ((value/=1) > 1 && value < 100) _rcset("cgi.width",value) 81 82 # Optional preferred output format. Add more formats as needed. 83 # This parameter is currently overloaded also with style- and 84 # alternate-type specs. 85 # 86 # Based on those values, 'lib/group-stuff.rc' will parse group+cf 87 # first and then look for group.alt-+cf . 88 89 value =_request("7",1) 90 if (value == "s") _rcset("cgi.outfmt","sitemap") 91 else if (value ~ /^(p(rint)?|alt-[a-z0-9][-a-z0-9]*)$/) 92 _rcset("cgi.style",value) 93 94 # Optional client-specified results per page. For this to work 95 # across paging, the pager() function needs to be modified to 96 # pass along this parameter to subsequent calls to groupPageMap. 97 # Short of that, this currently wors only on the first page 98 # of results. 99 if ((value=_request("8",1)/1) > 0) _rcset("cgi.blksize",value) 100 101 # The following test is necessary since the address could, 102 # at least in theory, have been set to any string by the 103 # remote user, due to how it is handled to cope with stunnel(8) 104 # and the lack of transproxy support in kernel 2.4.x. 105 106 if (_isipaddr(ENVIRON["REMOTE_ADDR"]) == _TRUE) 107 value = ENVIRON["REMOTE_ADDR"] 108 else value = "0.0.0.0" 109 110 _rcset("REMOTE_ADDR",value) 111 } 112 113 else { # response 114 115 outfile = _rcget("tpl.include.tw.page") 116 if (outfile !~ /^\/\.*[a-zA-Z0-9]/) 117 return(_sys("csaExit.fault 0041 outfile")) 118 119 fmt = readfmt("tw-group-pagemap") 120 gsub(/%/,"%%",fmt) # turn plain '%' into '%%'. 121 gsub(/\\/,"\\\\&",fmt) # turn '\' into '\\'. 122 gsub(/[\n\r]+/,"",fmt) # just in case. 123 tmp1 = fmt 124 125 # Handle custom positioning of output tokens. 126 sub(/.*\[:/,_NULL,tmp1); sub(/:].*/,_NULL,tmp1) 127 tmp1 = _strip(tmp1,_O_MIDDLE) 128 if (tmp1 ~ /^[0-7 ]+$/) tmp1 = tmp1 " 8" # compatibility. 129 if (tmp1 !~ /^[0-8 ]+$/) tmp1 = "1 2 3 4 5 6 7 8" 130 131 # pad missing arg specs with "0". 132 if ((i=split(tmp1,f," ")) < 8) { 133 while (i++ <= 8) tmp1 = tmp1 " 0" 134 i = split(tmp1,f," ") 135 } 136 137 tmp1 = _NULL 138 139 for (j=1; j<=i; j++) { 140 if (j > 8) break # ignore excess arg specs. 141 if (!sub(//,"%s",fmt)) fmt = fmt "" 142 tmp1 = tmp1 " " f[j] 143 } 144 145 # encode any extra markers. 146 gsub(//,"\\<tw:s/\\>",fmt) 147 148 fmt = fmt "\n" 149 150 split(_strip(tmp1),f," "); f[0] = 0 151 152 # Set subcat output format string. 153 154 fmt1 = readfmt("tw-group-pagemap-subcat") 155 gsub(/%/,"%%",fmt1) # turn plain '%' into '%%'. 156 gsub(/\\/,"\\\\&",fmt1) # turn '\' into '\\'. 157 gsub(/[\n\r]+/,"",fmt1) # just in case. 158 tmp1 = fmt1 159 160 # Handle custom positioning of output tokens. 161 sub(/.*\[:/,_NULL,tmp1); sub(/:].*/,_NULL,tmp1) 162 tmp1 = _strip(tmp1,_O_MIDDLE) 163 if (tmp1 ~ /^[0-8 ]+$/) tmp1 = tmp1 " 9" # compatibility. 164 if (tmp1 !~ /^[0-9 ]+$/) tmp1 = "1 2 3 4 5 6 7 8 9" 165 166 # pad missing arg specs with "0". 167 if ((i=split(tmp1,f1," ")) < 9) { 168 while (i++ <= 9) tmp1 = tmp1 " 0" 169 i = split(tmp1,f1," ") 170 } 171 172 tmp1 = _NULL 173 174 for (j=1; j<=i; j++) { 175 if (j > 9) break # ignore excess arg specs. 176 if (!sub(//,"%s",fmt1)) fmt1 = fmt1 "" 177 tmp1 = tmp1 " " f1[j] 178 } 179 180 # encode any extra markers. 181 gsub(//,"\\<tw:s/\\>",fmt1) 182 183 fmt1 = fmt1 "\n" 184 185 split(_strip(tmp1),f1," "); f1[0] = 0 186 187 # Set subcat block 1st-page output format string. 188 189 fmt3 = readfmt("tw-group-pagemap-subcat-first") 190 gsub(/%/,"%%",fmt3) # turn plain '%' into '%%'. 191 gsub(/\\/,"\\\\&",fmt3) # turn '\' into '\\'. 192 gsub(/[\n\r]+/,"",fmt3) # just in case. 193 tmp1 = fmt3 194 195 # Handle custom positioning of output tokens. 196 sub(/.*\[:/,_NULL,tmp1); sub(/:].*/,_NULL,tmp1) 197 tmp1 = _strip(tmp1,_O_MIDDLE) 198 if (tmp1 !~ /^[0-9 ]+$/) tmp1 = "1 2 3 4 5 6 7 8 9" 199 200 # pad missing arg specs with "0". 201 if ((i=split(tmp1,f3," ")) < 9) { 202 while (i++ <= 9) tmp1 = tmp1 " 0" 203 i = split(tmp1,f3," ") 204 } 205 206 tmp1 = _NULL 207 208 for (j=1; j<=i; j++) { 209 if (j > 9) break # ignore excess arg specs. 210 if (!sub(//,"%s",fmt3)) fmt3 = fmt3 "" 211 tmp1 = tmp1 " " f3[j] 212 } 213 214 # encode any extra markers. 215 gsub(//,"\\<tw:s/\\>",fmt3) 216 217 fmt3 = fmt3 "\n" 218 219 split(_strip(tmp1),f3," "); f3[0] = 0 220 221 # Set format string for store-type entries. 222 223 if (ENVIRON["TNS_BUY_CART"] == "paypal") 224 fmt4 = readfmt("tw-group-pagemap-shop-paypal") 225 else fmt4 = readfmt("tw-group-pagemap-shop") 226 227 gsub(/%/,"%%",fmt4) # turn plain '%' into '%%'. 228 gsub(/\\/,"\\\\&",fmt4) # turn '\' into '\\'. 229 gsub(/[\n\r]+/,"",fmt4) # just in case. 230 tmp1 = fmt4 231 232 # Handle custom positioning of output tokens. 233 sub(/.*\[:/,_NULL,tmp1); sub(/:].*/,_NULL,tmp1) 234 tmp1 = _strip(tmp1,_O_MIDDLE) 235 if (tmp1 !~ /^[0-6 ]+$/) tmp1 = "1 2 3 4 5 6" 236 237 # This format string may end up inside a comment block of the 238 # parent template, so it may not contain its own comments or 239 # the XML well-formedness may break. Note that this can be done 240 # only after we have consumed the argument positioning specs. 241 242 gsub(/-->/,"\001>",fmt4) 243 gsub(//,_NULL,fmt4) 244 gsub(/\001>/,"-->",fmt4) # restore orphans. 245 246 # pad missing arg specs with "0". 247 if ((i=split(tmp1,f4," ")) < 6) { 248 while (i++ <= 6) tmp1 = tmp1 " 0" 249 i = split(tmp1,f4," ") 250 } 251 252 tmp1 = _NULL 253 254 for (j=1; j<=i; j++) { 255 if (j > 6) break # ignore excess arg specs. 256 if (!sub(//,"%s",fmt4)) fmt4 = fmt4 "" 257 tmp1 = tmp1 " " f4[j] 258 } 259 260 # encode any extra markers. 261 gsub(//,"\\<tw:s/\\>",fmt4) 262 263 split(_strip(tmp1),f4," "); f4[0] = 0 264 265 stem = ENVIRON["CSA_RPC_URI"] "/" \ 266 ENVIRON["CSA_LANG"] "/" \ 267 _rcget("tbl_group.g_uri") 268 269 # trigger paging if appropriate. 270 if ((blkno=_rcget("cgi.paging"))) { 271 if ((blksize=_rcget("cgi.blksize",1)) == _NULL) 272 blksize = _rcget("TNS_PAGER_BLKSIZE",1) 273 if ((blksize/=1) <= 0) blksize = 10 274 first = blkno * blksize - blksize + 1 275 last = first + blksize - 1 276 } 277 278 # Make sure output file is cleared, in case we are re-using 279 # an old temporary file and we have nothing to print to it. 280 _creat(outfile,_O_TRUNC) 281 282 # read input table: 283 # p_uri,p_name,p_descr,k_page,\ 284 # p_vtime,k_node,p_link,p_store,p_ctime,p_tags,p_etime 285 286 e[0] = _NULL 287 i=j=n=1 288 w = _rcget("cgi.width",1) 289 r = _rcget("cgi.outfmt",1) 290 291 while (split(_TBLS[1,i++],a,"\t")) { 292 293 # Handle page expiration dates, accounting for older 294 # versions of page+dat which may lack that field. 295 296 # Set default expiration date. 297 if (a[11] == "") a[11] = "9999-12-31 23:59:59" 298 if (ENVIRON["CSA_TIME_ISO"] >= a[11] && \ 299 a[3] !~ /^ *-/) a[3] = "-" a[3] 300 301 # Hidden pages with no title will not appear in the listing 302 # to anybody, while hidden pages with non-null title will 303 # appear in the listing only to editors. 304 305 if (a[3] ~ /^ *-[- ]*$/) continue 306 else if (a[3] ~ /^ *-[- ]*[^- ]/ && \ 307 "," ENVIRON["TNS_AUTH_GRP"] "," !~ /,editor,/) continue 308 309 # Decide whether to exclude redirected pages from output. 310 if (a[3] ~ /\(:redirect.*:\)/ && 311 _bool(_rcget("TNS_REDIR_PROP",2)) == _TRUE) continue 312 313 # Handle store-type items. 314 if (split(a[8],c,/ +/)) { 315 316 # Set default shipping amount if missing. 317 if (c[3] == _NULL) c[3] = "0" 318 319 split(c[1],d,":") 320 321 # Force default unit of measure if missing. 322 if (d[3] == _NULL) d[3] = _nlsmap(_NULL,"units") 323 324 tmp2 = d[1] ":" d[2] ":" d[3] 325 326 # Normalize decimal separators. 327 gsub(/,/,".",c[2]) 328 329 split(c[2],d,":") 330 331 # Set default secondary price if missing. 332 if (d[2] == _NULL) d[2] = d[1] 333 334 # Set default VAT percentage if missing. 335 if (d[3] == _NULL) d[3] = 20 336 337 # Rebuild the complete normalized store field. 338 a[8] = tmp2 " " d[1] ":" d[2] ":" d[3] " " c[3] 339 } 340 341 # "I'm Feeling Lucky" function. 342 if (_TBLS[1,0] == 1 && \ 343 _bool(_rcget("TNS_GROUP_MISC_PROP",10)) == _TRUE) 344 _sys("csaExit.location " stem "/" a[1]) 345 346 # Handle output paging. 347 if (blkno && ++tot && (++curr < first || curr > last)) continue 348 349 url = stem "/" a[1] 350 351 # Remove any redirection URL from visible description. 352 sub(/ *\+*\(:redirect .*/,_NULL,a[3]) 353 354 # Remove any explicit exclusion directive. 355 sub(/^ *! */,_NULL,a[3]) 356 357 if (_strip(a[3],_O_MIDDLE) == _strip(a[2],_O_MIDDLE)) a[3] = _NULL 358 359 if (a[3] == _NULL) a[3] = a[2] # default descr. 360 361 if (r == "sitemap") { 362 tmp = a[5] 363 if (tmp !~ /^[0-9],/) tmp = "0," tmp # default ranking 364 sub(/,.*/,_NULL,tmp) 365 # Retain only YYYY-MM-DD for old p_ctime values 366 # that are not in ISO8601 format. 367 tmp1 = a[9] 368 sub(/ .*/,_NULL,tmp1) 369 printf("\n%s\n%s\n%.1f\n\n",_xmlencode(url),tmp1,tmp) > outfile 370 continue 371 } 372 373 # Display the "buy" link where applicable. 374 375 split(a[8],b,/[ :]/) 376 377 if (b[2]) { 378 379 if (ENVIRON["TNS_BUY_CART"] == "paypal") { 380 381 # If the PayPal Shopping Cart is being used, then item 382 # price will include VAT and the shipping amount, if any, 383 # will default to the one of the first (or only) shipping 384 # method supported. PayPal prices always include VAT, as it 385 # is quite unlikely that the merchant will use PayPal also 386 # for the invoicing process as opposed to using her own 387 # usual ERP system. 388 389 if (_bool(ENVIRON["TNS_BUY_PRICE_HAS_VAT"]) == _TRUE) { 390 e[1] = b[4] 391 e[2] = b[5] 392 e[6] = sprintf("%.2f",b[7]) 393 } 394 else { 395 e[1] = sprintf("%.2f",b[4]+(b[4]/100*b[6])) 396 e[2] = sprintf("%.2f",b[5]+(b[5]/100*b[6])) 397 e[6] = sprintf("%.2f",\ 398 b[7]+b[7]/100*ENVIRON["TNS_BUY_SHIP_VAT"]) 399 } 400 } 401 402 else { 403 e[1] = b[4] 404 e[2] = b[5] 405 e[6] = sprintf("%.2f",b[7]) 406 } 407 408 e[3] = stem "/tw-cart" 409 #e[4] = b[1] 410 e[4] = a[4] 411 e[5] = _xmlencode(a[2]) 412 buy = sprintf(fmt4,e[f4[1]],\ 413 e[f4[2]],e[f4[3]],e[f4[4]],e[f4[5]],e[f4[6]]) 414 } 415 else buy = _NULL 416 417 # Pick the appropriate format string depending on whether this 418 # is a subcat entry or not. 419 420 if (split(a[2],b,".") > 1 && (tmp1=getcat(a[2])) != _NULL) { 421 tmp3 = b[1] # save for later 422 b[2] = a[2] 423 if (tmp1 != _NULL) { 424 tmp1 = "^" _escreg(tmp1 ".") 425 sub(tmp1,_NULL,b[2]) # compute trail. 426 } 427 # not 1st page in subcat block. 428 if (b[1] == oldcat) { 429 e[1] = _xmlencode(url) 430 e[2] = _xmlencode(b[1]) 431 e[3] = _xmlencode(b[2]) 432 e[4] = _xmlencode(a[3]) 433 e[5] = a[4] 434 e[6] = a[4]; sub(/^[^.]+\./,_NULL,e[6]) 435 e[7] = _xmlencode(a[7]) 436 e[8] = buy 437 e[9] = _xmlencode(a[10]) 438 printf(fmt1,e[f1[1]],e[f1[2]],e[f1[3]],e[f1[4]],\ 439 e[f1[5]],e[f1[6]],e[f1[7]],e[f1[8]],e[f1[9]]) > outfile 440 } 441 else { 442 # 1st page in subcat block. 443 e[1] = _xmlencode(b[1]) 444 e[2] = _xmlencode(url) 445 e[3] = _xmlencode(a[10]) 446 e[4] = _xmlencode(b[2]) 447 e[5] = _xmlencode(a[3]) 448 e[6] = a[4] 449 e[7] = a[4]; sub(/^[^.]+\./,_NULL,e[7]) 450 e[8] = _xmlencode(a[7]) 451 e[9] = buy 452 printf(fmt3,e[f3[1]],e[f3[2]],e[f3[3]],e[f3[4]],\ 453 e[f3[5]],e[f3[6]],e[f3[7]],e[f3[8]],e[f3[9]]) > outfile 454 oldcat = b[1] 455 } 456 } 457 else { 458 e[1] = _xmlencode(url) 459 e[2] = _xmlencode(a[2]) 460 e[3] = _xmlencode(a[3]) 461 e[4] = a[4] 462 e[5] = a[4]; sub(/^[^.]+\./,_NULL,e[5]) 463 e[6] = _xmlencode(a[7]) 464 e[7] = buy 465 e[8] = _xmlencode(a[10]) 466 printf(fmt,e[f[1]],e[f[2]],\ 467 e[f[3]],e[f[4]],e[f[5]],e[f[6]],e[f[7]],e[f[8]]) > outfile 468 } 469 470 # Handle tiled output if requested. 471 if (w > 1 && ++n > w) { 472 print _rcget("TNS_GROUP_MISC_PROP",1) > outfile 473 n = 1 474 } 475 476 # Provide also a machine-readable format. 477 _wsresponse(1,j++,url) 478 } 479 480 close(outfile) 481 482 # show the pager if appropriate. 483 if (blkno && tot > blksize) { 484 485 # Set pager output format string. 486 487 fmt2 = readfmt("tw-pager") 488 gsub(/%/,"%%",fmt2) # turn plain '%' into '%%'. 489 gsub(/\\/,"\\\\&",fmt2) # turn '\' into '\\'. 490 gsub(/[\n\r]+/,"",fmt2) # just in case. 491 492 # the pager format string is currently not customizable. 493 if (!sub(//,"%s",fmt2)) fmt2 = fmt2 "" 494 if (!sub(//,"%s",fmt2)) fmt2 = fmt2 "" 495 496 # encode any extra markers. 497 gsub(//,"\\<tw:s/\\>",fmt2) 498 499 fmt2 = fmt2 "\n" 500 501 url = ENVIRON["CSA_RPC_URI"] "/" \ 502 ENVIRON["CSA_LANG"] "/" \ 503 _rcget("tbl_group.g_uri") "/5" 504 505 if ((tmp=_rcget("cgi.subcat")) != _NULL) url = url "/" tmp "/" 506 else url = url "?3=" 507 508 tot % blksize ? tmp = 1 : tmp = 0 509 510 _response("tpl.var.tw.pager",\ 511 pager(blkno,int(tot/blksize)+tmp,url,fmt2)) 512 } 513 514 # Notes on how the resulting meta description is built: 515 # 516 # 1) If the normal site map w/o subcat spec was requested, 517 # then cgi.subcat is empty and only the group description 518 # will be used. 519 # 520 # 2) If an exact subcat was specified, then all listed pages 521 # belong into that subcat and tmp2 will contain the literal 522 # subcat name, taken from the last page listed. 523 # 524 # 3) If a fuzzy search was requested, I'll use the search term 525 # for the meta description, as the listing will usually contain 526 # pages belonging into different subcats. This is OK, because 527 # the view resulting from a fuzzy match is meant only for human 528 # consumption, while search engines do not enter search strings 529 # but simply descend along site maps one anchor after the other, 530 # so the subcat name seen by crawlers will always fall in either 531 # (1) or (2) above. 532 533 value = _rcget("tbl_group.g_descr") 534 535 if (_rcget("cgi.subcat") != _NULL) { 536 if (_rcget("cgi.scope") ~ /^[fF]/) 537 value = value ": " _rcget("cgi.subcat.literal") 538 else value = value ": " tmp3 539 } 540 541 if (value !~ /: /) 542 value = value ": " _nlsmap(_NULL,"site map") 543 544 _response("tpl.var.tw.meta", "") 546 547 # Set also a consistent page title. 548 _response("tpl.var.html.title", value) 549 550 # generic template conditionals. 551 552 ifsections() 553 } 554 } 555 556 # EOF