1# Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/ 2# 3# Copyright (C) 2000-2018 Peter Thoeny, peter[at]thoeny.org 4# and TWiki Contributors. All Rights Reserved. TWiki Contributors 5# are listed in the AUTHORS file in the root of this distribution. 6# NOTE: Please extend that file, not this notice. 7# 8# This program is free software; you can redistribute it and/or 9# modify it under the terms of the GNU General Public License 10# as published by the Free Software Foundation; either version 3 11# of the License, or (at your option) any later version. For 12# more details read LICENSE in the root of this distribution. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 17# 18# As per the GPL, removal of this notice is prohibited. 19 20=pod 21 22---+ Package TWiki::Func 23 24<!-- STARTINCLUDE required for huge TWikiDocumentation topic --> 25%STARTINCLUDE% 26 27_Official list of stable TWiki functions for Plugin developers_ 28 29This module defines official functions that [[%SYSTEMWEB%.TWikiPlugins][TWiki plugins]] 30can use to interact with the TWiki engine and content. 31 32Refer to TWiki.EmptyPlugin and lib/TWiki/Plugins/EmptyPlugin.pm for a template 33plugin and documentation on how to write a plugin. 34 35Plugins should *only* use functions published in this module. If you use 36functions in other TWiki libraries you might create a security hole and 37you will probably need to change your plugin when you upgrade TWiki. 38 39Deprecated functions will still work in older code, though they should 40_not_ be called in new plugins and should be replaced in older plugins 41as soon as possible. 42 43The version of the TWiki::Func module is defined by the VERSION number of the 44TWiki::Plugins module, currently %PLUGINVERSION%. This can be shown 45by the =%<nop>PLUGINVERSION%= TWiki variable, and accessed in code using 46=$TWiki::Plugins::VERSION=. The 'Since' field in the function 47documentation refers to =$TWiki::Plugins::VERSION=. 48 49Notes on use of =$TWiki::Plugins::VERSION= 6.00 and later: 50 51 * The version number is now aligned with the TWiki release version. 52 * A TWiki-6.7.8 release will have a =$TWiki::Plugins::VERSION = 6.78=. 53 * In an unlikely case where the patch number is 10 or larger, the patch 54 number is added to the previous patch number. For example, TWiki-6.7.9 55 will have version =6.79=, TWiki-6.7.10 will have =6.7910=, and 56 TWiki-6.7.11 will have =6.7911=. This ensures that the version number 57 can sort properly. 58 * =TWiki::Plugins::VERSION= also applies to the plugin handlers. The 59 handlers are documented in the !EmptyPlugin, and that module indicates 60 what version of =TWiki::Plugins::VERSION= it relates to. 61 62A full history of the changes to this API can be found at the end of this 63topic. 64 65=cut 66 67package TWiki::Func; 68 69use strict; 70use Error qw( :try ); 71use Assert; 72 73require TWiki; 74require TWiki::Plugins; 75require TWiki::UI; 76 77=pod 78 79#EnvironmentFunctions 80---++ Environment 81 82=cut 83 84=pod 85 86#GetSkin 87---+++ getSkin( ) -> $skin 88 89Get the skin path, set by the =SKIN= and =COVER= preferences variables or the =skin= and =cover= CGI parameters 90 91Return: =$skin= Comma-separated list of skins, e.g. ='gnu,tartan'=. Empty string if none. 92 93*Since:* TWiki::Plugins::VERSION 1.000 (29 Jul 2001) 94 95=cut 96 97sub getSkin { 98 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 99 100 return $TWiki::Plugins::SESSION->getSkin(); 101} 102 103=pod 104 105#GetUrlHost 106---+++ getUrlHost( ) -> $host 107 108Get protocol, domain and optional port of script URL 109 110Return: =$host= URL host, e.g. ="http://example.com:80"= 111 112*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 113 114=cut 115 116sub getUrlHost { 117 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 118 119 return $TWiki::Plugins::SESSION->{urlHost}; 120} 121 122=pod 123 124#GetScriptUrl 125---+++ getScriptUrl( $web, $topic, $script, ... ) -> $url 126 127Compose fully qualified URL 128 * =$web= - Web name, e.g. ='Main'= 129 * =$topic= - Topic name, e.g. ='WebNotify'= 130 * =$script= - Script name, e.g. ='view'= 131 * =...= - an arbitrary number of name=>value parameter pairs that will be url-encoded and added to the url. The special parameter name '#' is reserved for specifying an anchor. e.g. <tt>getScriptUrl('x','y','view','#'=>'XXX',a=>1,b=>2)</tt> will give <tt>.../view/x/y?a=1&b=2#XXX</tt> 132 133Return: =$url= URL, e.g. ="http://example.com:80/cgi-bin/view.pl/Main/WebNotify"= 134 135*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 136 137=cut 138 139sub getScriptUrl { 140 my $web = shift; 141 my $topic = shift; 142 my $script = shift; 143 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 144 145 return $TWiki::Plugins::SESSION->getScriptUrl( 1, $script, $web, $topic, @_ ); 146} 147 148=pod 149 150#GetViewUrl 151---+++ getViewUrl( $web, $topic ) -> $url 152 153Compose fully qualified view URL 154 * =$web= - Web name, e.g. ='Main'=. The current web is taken if empty 155 * =$topic= - Topic name, e.g. ='WebNotify'= 156Return: =$url= URL, e.g. ="http://example.com:80/cgi-bin/view.pl/Main/WebNotify"= 157 158*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 159 160=cut 161 162sub getViewUrl { 163 my( $web, $topic ) = @_; 164 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 165 166 $web ||= $TWiki::Plugins::SESSION->{webName} || $TWiki::cfg{UsersWebName}; 167 return getScriptUrl( $web, $topic, 'view' ); 168} 169 170=pod 171 172#GetPubUrlPath 173---+++ getPubUrlPath( ) -> $path 174 175Get pub URL path 176 177Return: =$path= URL path of pub directory, e.g. ="/pub"= 178 179*Since:* TWiki::Plugins::VERSION 1.000 (14 Jul 2001) 180 181=cut 182 183sub getPubUrlPath { 184 return $TWiki::cfg{PubUrlPath}; 185} 186 187=pod 188 189#GetExternalResource 190---+++ getExternalResource( $url, \@headers, \%params ) -> $response 191 192Get whatever is at the other end of a URL (using an HTTP GET request). Will 193only work for encrypted protocols such as =https= if the =LWP= CPAN module is 194installed. 195 196Note that the =$url= may have an optional user and password, as specified by 197the relevant RFC. Any proxy set in =configure= is honored. 198 199Optional parameters may be supplied: 200 * =\@headers= (an array ref): Additional HTTP headers of form 'name1', 201 'value1', 'name2', 'value2'. 202 User-Agent header is set to "TWiki::Net/### libwww-perl/#.##" by default, 203 where ### is the revision number of TWiki::Net and #.## is the version 204 of LWP. 205 * =\%params= (a hash ref): Additional options. 206 207Below is the list of available =%params=. See CPAN:LWP::UserAgent for more 208details. 209| *Name* | *Usage* | 210| =agent= | ==> $useragent= ("User-Agent:" header) | 211| =cookie_jar= | ==> $cookies= | 212| =credentials= | ==> [$netloc, $realm, $uname, $pass]= | 213| =handlers= | ==> {$phase => \&cb, ...}= \ 214 Note: =%matchspec= is not available. | 215| =local_address= | ==> $address= | 216| =max_redirect= | ==> $n= | 217| =max_size= | ==> $bytes= | 218| =method= * | ==> $method= E.g. 'HEAD' | 219| =parse_head= | ==> $boolean= | 220| =requests_redirectable= | ==> \@requests= | 221| =ssl_opts= | ==> {$key => $value, ...}= | 222| =timeout= * | ==> $secs= | 223The parameters with * do not require =LWP=. 224 225Example: 226<verbatim> 227my $response = getExternalResource($url, 228 ['Cache-Control' => 'max-age=0'], {timeout => 10}); 229</verbatim> 230 231The =$response= is an object that is known to implement the following subset of 232the methods of =HTTP::Response=. It may in fact be an =HTTP::Response= object, 233but it may also not be if =LWP= is not available, so callers may only assume 234the following subset of methods is available: 235| =code()= | 236| =message()= | 237| =header($field)= | 238| =content()= | 239| =is_error()= | 240| =is_redirect()= | 241 242Note that if LWP is *not* available, this function: 243 1 can only really be trusted for HTTP/1.0 urls. If HTTP/1.1 or another 244 protocol is required, you are *strongly* recommended to =require LWP=. 245 1 Will not parse multipart content 246 247In the event of the server returning an error, then =is_error()= will return 248true, =code()= will return a valid HTTP status code 249as specified in RFC 2616 and RFC 2518, and =message()= will return the 250message that was received from 251the server. In the event of a client-side error (e.g. an unparseable URL) 252then =is_error()= will return true and =message()= will return an explanatory 253message. =code()= will return 400 (BAD REQUEST). 254 255Note: Callers can easily check the availability of other HTTP::Response methods 256as follows: 257 258<verbatim> 259my $response = TWiki::Func::getExternalResource($url); 260if (!$response->is_error() && $response->isa('HTTP::Response')) { 261 $text = $response->content(); 262 # ... other methods of HTTP::Response may be called 263} else { 264 # ... only the methods listed above may be called 265} 266</verbatim> 267 268*Since:* TWiki::Plugins::VERSION 1.2 269 270__Note:__ The optional parameters \@headers and \%params were added in 271TWiki::Plugins::VERSION 6.00 272 273=cut 274 275sub getExternalResource { 276 my( $url, @options ) = @_; 277 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 278 ASSERT(defined $url) if DEBUG; 279 280 return $TWiki::Plugins::SESSION->net->getExternalResource( $url, @options ); 281} 282 283=pod 284 285#PostExternalResource 286---+++ postExternalResource( $url, $text, \@headers, \%params ) -> $response 287 288This method is essentially the same as =getExternalResource()= except that it uses 289an HTTP POST method and that the additional =$text= parameter is required. 290 291The =$text= is sent to the server as the body content of the HTTP request. 292 293See =getExternalResource()= for more details. 294 295*Since:* TWiki::Plugins::VERSION 6.00 296 297=cut 298 299sub postExternalResource { 300 my( $url, $text, @options ) = @_; 301 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 302 ASSERT(defined $url) if DEBUG; 303 304 return $TWiki::Plugins::SESSION->net->postExternalResource( $url, $text, @options ); 305} 306 307=pod 308 309#GetCgiQuery 310---+++ getCgiQuery( ) -> $query 311 312Get CGI query object. Important: Plugins cannot assume that scripts run under CGI, Plugins must always test if the CGI query object is set 313 314Return: =$query= CGI query object; or 0 if script is called as a shell script 315 316*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 317 318=cut 319 320sub getCgiQuery { 321 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 322 return $TWiki::Plugins::SESSION->{request}; 323} 324 325=pod 326 327#GetSessionKeys 328---+++ getSessionKeys() -> @keys 329Get a list of all the names of session variables. The list is unsorted. 330 331Session keys are stored and retrieved using =setSessionValue= and 332=getSessionValue=. 333 334*Since:* TWiki::Plugins::VERSION 1.2 335 336=cut 337 338sub getSessionKeys { 339 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 340 my $hash = $TWiki::Plugins::SESSION->{users}->{loginManager}->getSessionValues(); 341 return keys %{$hash}; 342} 343 344=pod 345 346#GetSessionValue 347---+++ getSessionValue( $key ) -> $value 348 349Get a session value from the client session module 350 * =$key= - Session key 351Return: =$value= Value associated with key; empty string if not set 352 353*Since:* TWiki::Plugins::VERSION 1.000 (27 Feb 200) 354 355=cut 356 357sub getSessionValue { 358# my( $key ) = @_; 359 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 360 361 return $TWiki::Plugins::SESSION->{users}->{loginManager}->getSessionValue( @_ ); 362} 363 364 365=pod 366 367#SetSessionValue 368---+++ setSessionValue( $key, $value ) -> $boolean 369 370Set a session value. 371 * =$key= - Session key 372 * =$value= - Value associated with key 373Return: true if function succeeded 374 375*Since:* TWiki::Plugins::VERSION 1.000 (17 Aug 2001) 376 377=cut 378 379sub setSessionValue { 380# my( $key, $value ) = @_; 381 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 382 383 $TWiki::Plugins::SESSION->{users}->{loginManager}->setSessionValue( @_ ); 384} 385 386=pod 387 388#ClearSessionValue 389---+++ clearSessionValue( $key ) -> $boolean 390 391Clear a session value that was set using =setSessionValue=. 392 * =$key= - name of value stored in session to be cleared. Note that 393 you *cannot* clear =AUTHUSER=. 394Return: true if the session value was cleared 395 396*Since:* TWiki::Plugins::VERSION 1.1 397 398=cut 399 400sub clearSessionValue { 401 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 402 403 return $TWiki::Plugins::SESSION->{users}->{loginManager}->clearSessionValue( @_ ); 404} 405 406=pod 407 408#GetContext 409---+++ getContext() -> \%hash 410 411Get a hash of context identifiers representing the currently active 412context. 413 414The context is a set of identifiers that are set 415during specific phases of TWiki processing. For example, each of 416the standard scripts in the 'bin' directory each has a context 417identifier - the view script has 'view', the edit script has 'edit' 418etc. So you can easily tell what 'type' of script your Plugin is 419being called within. The core context identifiers are listed 420in the %SYSTEMWEB%.IfStatements topic. Please be careful not to 421overwrite any of these identifiers! 422 423Context identifiers can be used to communicate between Plugins, and between 424Plugins and templates. For example, in FirstPlugin.pm, you might write: 425<verbatim> 426sub initPlugin { 427 TWiki::Func::getContext()->{'MyID'} = 1; 428 ... 429</verbatim> 430This can be used in !SecondPlugin.pm like this: 431<verbatim> 432sub initPlugin { 433 if( TWiki::Func::getContext()->{'MyID'} ) { 434 ... 435 } 436 ... 437</verbatim> 438or in a template, like this: 439<verbatim> 440%TMPL:DEF{"ON"}% Not off %TMPL:END% 441%TMPL:DEF{"OFF"}% Not on %TMPL:END% 442%TMPL:P{context="MyID" then="ON" else="OFF"}% 443</verbatim> 444or in a topic: 445<verbatim> 446%IF{"context MyID" then="MyID is ON" else="MyID is OFF"}% 447</verbatim> 448__Note__: *all* plugins have an *automatically generated* context identifier 449if they are installed and initialised. For example, if the FirstPlugin is 450working, the context ID 'FirstPluginEnabled' will be set. 451 452*Since:* TWiki::Plugins::VERSION 1.1 453 454=cut 455 456sub getContext { 457 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 458 return $TWiki::Plugins::SESSION->{context}; 459} 460 461=pod 462 463#PushTopicContext 464---+++ pushTopicContext($web, $topic) 465 * =$web= - new web 466 * =$topic= - new topic 467Change the TWiki context so it behaves as if it was processing =$web.$topic= 468from now on. All the preferences will be reset to those of the new topic. 469Note that if the new topic is not readable by the logged in user due to 470access control considerations, there will *not* be an exception. It is the 471duty of the caller to check access permissions before changing the topic. 472 473It is the duty of the caller to restore the original context by calling 474=popTopicContext=. 475 476Note that this call does *not* re-initialise plugins, so if you have used 477global variables to remember the web and topic in =initPlugin=, then those 478values will be unchanged. 479 480*Since:* TWiki::Plugins::VERSION 1.2 481 482=cut 483 484sub pushTopicContext { 485 my $twiki = $TWiki::Plugins::SESSION; 486 ASSERT($twiki) if DEBUG; 487 my( $web, $topic ) = $twiki->normalizeWebTopicName( @_ ); 488 my $old = { 489 web => $twiki->{webName}, 490 topic => $twiki->{topicName}, 491 mark => $twiki->{prefs}->mark() }; 492 493 push( @{$twiki->{_FUNC_PREFS_STACK}}, $old ); 494 $twiki->{webName} = $web; 495 $twiki->{topicName} = $topic; 496 $twiki->{prefs}->pushWebPreferences( $web ); 497 $twiki->{prefs}->pushPreferences( $web, $topic, 'TOPIC' ); 498 $twiki->{prefs}->pushPreferenceValues( 499 'SESSION', $twiki->{users}->{loginManager}->getSessionValues() ); 500} 501 502=pod 503 504#PopTopicContext 505---+++ popTopicContext() 506 507Returns the TWiki context to the state it was in before the 508=pushTopicContext= was called. 509 510*Since:* TWiki::Plugins::VERSION 1.2 511 512=cut 513 514sub popTopicContext { 515 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 516 my $twiki = $TWiki::Plugins::SESSION; 517 ASSERT(scalar(@{$twiki->{_FUNC_PREFS_STACK}})) if DEBUG; 518 my $old = pop( @{$twiki->{_FUNC_PREFS_STACK}} ); 519 $twiki->{prefs}->restore( $old->{mark}); 520 $twiki->{webName} = $old->{web}; 521 $twiki->{topicName} = $old->{topic}; 522} 523 524=pod 525 526#PreferencesFunctions 527---++ Preferences 528 529=cut 530 531=pod 532 533#GetPreferencesValue 534---+++ getPreferencesValue( $key, $web ) -> $value 535 536Get a preferences value from TWiki or from a Plugin 537 * =$key= - Preferences key 538 * =$web= - Name of web, optional. Current web if not specified; does not apply to settings of Plugin topics 539Return: =$value= Preferences value; empty string if not set 540 541*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 542 543 * Example for Plugin setting: 544 * !MyPlugin topic has: =* Set COLOR = red= 545 * Use ="MYPLUGIN_COLOR"= for =$key= 546 * =my $color = TWiki::Func::getPreferencesValue( "MYPLUGIN_COLOR" );= 547 548 * Example for preferences setting: 549 * WebPreferences topic has: =* Set WEBBGCOLOR = #FFFFC0= 550 * =my $webColor = TWiki::Func::getPreferencesValue( 'WEBBGCOLOR', 'Sandbox' );= 551 552*NOTE:* As of TWiki-4.1, if =$NO_PREFS_IN_TOPIC= is enabled in the plugin, then 553preferences set in the plugin topic will be ignored. 554 555=cut 556 557sub getPreferencesValue { 558 my( $key, $web ) = @_; 559 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 560 if( $web ) { 561 return $TWiki::Plugins::SESSION->{prefs}->getWebPreferencesValue( 562 $key, $web ); 563 } else { 564 return $TWiki::Plugins::SESSION->{prefs}->getPreferencesValue( $key ); 565 } 566} 567 568=pod 569 570#GetPluginPreferencesValue 571---+++ getPluginPreferencesValue( $key ) -> $value 572 573Get a preferences value from your Plugin 574 * =$key= - Plugin Preferences key w/o PLUGINNAME_ prefix. 575Return: =$value= Preferences value; empty string if not set 576 577__Note__: This function will will *only* work when called from the Plugin.pm file itself. it *will not work* if called from a sub-package (e.g. TWiki::Plugins::MyPlugin::MyModule) 578 579*Since:* TWiki::Plugins::VERSION 1.021 (27 Mar 2004) 580 581*NOTE:* As of TWiki-4.1, if =$NO_PREFS_IN_TOPIC= is enabled in the plugin, then 582preferences set in the plugin topic will be ignored. 583 584=cut 585 586sub getPluginPreferencesValue { 587 my( $key ) = @_; 588 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 589 my $package = caller; 590 $package =~ s/.*:://; # strip off TWiki::Plugins:: prefix 591 return $TWiki::Plugins::SESSION->{prefs}->getPreferencesValue( "\U$package\E_$key" ); 592} 593 594=pod 595 596#GetPreferencesFlag 597---+++ getPreferencesFlag( $key, $web ) -> $value 598 599Get a preferences flag from TWiki or from a Plugin 600 * =$key= - Preferences key 601 * =$web= - Name of web, optional. Current web if not specified; does not apply to settings of Plugin topics 602Return: =$value= Preferences flag ='1'= (if set), or ="0"= (for preferences values ="off"=, ="no"= and ="0"=) 603 604*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 605 606 * Example for Plugin setting: 607 * !MyPlugin topic has: =* Set SHOWHELP = off= 608 * Use ="MYPLUGIN_SHOWHELP"= for =$key= 609 * =my $showHelp = TWiki::Func::getPreferencesFlag( "MYPLUGIN_SHOWHELP" );= 610 611*NOTE:* As of TWiki-4.1, if =$NO_PREFS_IN_TOPIC= is enabled in the plugin, then 612preferences set in the plugin topic will be ignored. 613 614=cut 615 616sub getPreferencesFlag { 617# my( $key, $web ) = @_; 618 my $t = getPreferencesValue( @_ ); 619 return TWiki::isTrue( $t ); 620} 621 622=pod 623 624#GetPluginPreferencesFlag 625---+++ getPluginPreferencesFlag( $key ) -> $boolean 626 627Get a preferences flag from your Plugin 628 * =$key= - Plugin Preferences key w/o PLUGINNAME_ prefix. 629Return: false for preferences values ="off"=, ="no"= and ="0"=, or values not set at all. True otherwise. 630 631__Note__: This function will will *only* work when called from the Plugin.pm file itself. it *will not work* if called from a sub-package (e.g. TWiki::Plugins::MyPlugin::MyModule) 632 633*Since:* TWiki::Plugins::VERSION 1.021 (27 Mar 2004) 634 635*NOTE:* As of TWiki-4.1, if =$NO_PREFS_IN_TOPIC= is enabled in the plugin, then 636preferences set in the plugin topic will be ignored. 637 638=cut 639 640sub getPluginPreferencesFlag { 641 my( $key ) = @_; 642 my $package = caller; 643 $package =~ s/.*:://; # strip off TWiki::Plugins:: prefix 644 return getPreferencesFlag( "\U$package\E_$key" ); 645} 646 647=pod 648 649#SetPreferencesValue 650---+++ setPreferencesValue($name, $val) 651 652Set the preferences value so that future calls to getPreferencesValue will 653return this value, and =%$name%= will expand to the preference when used in 654future variable expansions. 655 656The preference only persists for the rest of this request. Finalised 657preferences cannot be redefined using this function. 658 659Returns 1 if the preference was defined, and 0 otherwise. 660 661=cut 662 663sub setPreferencesValue { 664 return $TWiki::Plugins::SESSION->{prefs}->setPreferencesValue(@_); 665} 666 667=pod 668 669#GetWikiToolName 670---+++ getWikiToolName( ) -> $name 671 672Get toolname as defined in TWiki.cfg 673 674Return: =$name= Name of tool, e.g. ='TWiki'= 675 676*Since:* TWiki::Plugins::VERSION 1.000 (27 Feb 2001) 677 678=cut 679 680sub getWikiToolName { 681 return $TWiki::cfg{WikiToolName}; 682} 683 684=pod 685 686#GetMainWebname 687---+++ getMainWebname( ) -> $name 688 689Get name of Main web as defined in TWiki.cfg 690 691Return: =$name= Name, e.g. ='Main'= 692 693*Since:* TWiki::Plugins::VERSION 1.000 (27 Feb 2001) 694 695=cut 696 697sub getMainWebname { 698 return $TWiki::cfg{UsersWebName}; 699} 700 701=pod 702 703#GetTwikiWebname 704---+++ getTwikiWebname( ) -> $name 705 706Get name of TWiki documentation web as defined in TWiki.cfg 707 708Return: =$name= Name, e.g. ='TWiki'= 709 710*Since:* TWiki::Plugins::VERSION 1.000 (27 Feb 2001) 711 712=cut 713 714sub getTwikiWebname { 715 return $TWiki::cfg{SystemWebName}; 716} 717 718=pod 719 720#UserHandlingAndAccessControlFunctions 721#UserHandlingFunctions 722---++ User Handling and Access Control 723 724#GetDefaultUserName 725---+++ getDefaultUserName( ) -> $loginName 726Get default user name as defined in the configuration as =DefaultUserLogin= 727 728Return: =$loginName= Default user name, e.g. ='guest'= 729 730*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 731 732=cut 733 734sub getDefaultUserName { 735 return $TWiki::cfg{DefaultUserLogin}; 736} 737 738=pod 739 740#GetCanonicalUserID 741---+++ getCanonicalUserID( $user ) -> $cUID 742 * =$user= can be a login, wikiname or web.wikiname 743Return the cUID of the specified user. A cUID is a unique identifier which 744is assigned by TWiki for each user. 745BEWARE: While the default TWikiUserMapping uses a cUID that looks like a user's 746LoginName, some characters are modified to make them compatible with rcs. 747Other usermappings may use other conventions - the !JoomlaUserMapping 748for example, has cUIDs like 'JoomlaeUserMapping_1234'. 749 750If $user is undefined, it assumes the currently logged-in user. 751 752Return: =$cUID=, an internal unique and portable escaped identifier for 753registered users. This may be autogenerated for an authenticated but 754unregistered user. 755 756*Since:* TWiki::Plugins::VERSION 1.2 757 758=cut 759 760sub getCanonicalUserID { 761 my $user = shift; 762 return $TWiki::Plugins::SESSION->{user} unless ($user); 763 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 764 my $cUID; 765 if ($user) { 766 $cUID = 767 $TWiki::Plugins::SESSION->{users}->getCanonicalUserID( $user ); 768 if (!$cUID) { 769 # Not a login name or a wiki name. Is it a valid cUID? 770 my $ln = $TWiki::Plugins::SESSION->{users}->getLoginName($user); 771 $cUID = $user if defined $ln && $ln ne 'unknown'; 772 } 773 } else { 774 $cUID = $TWiki::Plugins::SESSION->{user}; 775 } 776 return $cUID; 777} 778 779=pod 780 781#GetWikiName 782---+++ getWikiName( $user ) -> $wikiName 783 784Return the WikiName of the specified user. 785If $user is undefined get Wiki name of logged-in user. 786 787 * $user can be a cUID, login, wikiname or web.wikiname 788 789Return: =$wikiName= Wiki Name, e.g. ='JohnDoe'= 790 791*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 792 793=cut 794 795sub getWikiName { 796 my $user = shift; 797 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 798 # | *Mapping* | *cUID* | *login* | *wikiname* | 799 # | TWikiUserMapping | JoeSchmoe | JoeSchmoe | JoeSchmoe | 800 # | CustomUserMapping | CM_jschmoe | jschmoe | JoeSchmoe | 801 # TWikiUserMapping: 802 # $users->getLoginName('JoeSchmoe') -> 'JoeSchmoe' 803 # $users->getLoginName('NotExist') -> undef 804 # CustomUsrMapping: 805 # $users->getLoginName('JoeSchmoe') -> undef 806 # $users->getLoginName('NotExist') -> undef 807 # $users->getLoginName('CM_jschmoe')-> 'jschmoe' 808 # $users->getLoginName('jschmoe') -> undef 809 # Given this, getLoginName() is used to check if $user is cUID 810 my $users = $TWiki::Plugins::SESSION->{users}; 811 my $ln = $users->getLoginName($user); 812 my $cUID; 813 if ( defined($ln) && $ln ne 'unknown' ) { 814 # $user is a cUID 815 $cUID = $user; 816 } 817 else { 818 $cUID = getCanonicalUserID( $user ); 819 unless( defined $cUID ) { 820 my ($w, $u) = 821 normalizeWebTopicName($TWiki::cfg{UsersWebName}, $user); 822 return $u; 823 } 824 } 825 return $TWiki::Plugins::SESSION->{users}->getWikiName( $cUID ); 826} 827 828=pod 829 830#GetWikiUserName 831---+++ getWikiUserName( $user ) -> $wikiName 832 833Return the userWeb.WikiName of the specified user. 834If $user is undefined get Wiki name of logged-in user. 835 836 * $user can be a cUID, login, wikiname or web.wikiname 837 838Return: =$wikiName= Wiki Name, e.g. ="Main.JohnDoe"= 839 840*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 841 842=cut 843 844sub getWikiUserName { 845 my $user = shift; 846 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 847 my $cUID = getCanonicalUserID( $user ); 848 unless( defined $cUID ) { 849 my ($w, $u) = normalizeWebTopicName($TWiki::cfg{UsersWebName}, $user); 850 return "$w.$u"; 851 } 852 return $TWiki::Plugins::SESSION->{users}->webDotWikiName($cUID); 853} 854 855=pod 856 857#WikiToUserName 858---+++ wikiToUserName( $id ) -> $loginName 859Translate a Wiki name to a login name. 860 * =$id= - Wiki name, required, e.g. ='Main.JohnDoe'= or ='JohnDoe'=. 861 Since TWiki 4.2.1, $id may also be a login name. This will normally 862 be transparent, but should be borne in mind if you have login names 863 that are also legal wiki names. 864 865Return: =$loginName= Login name of user, e.g. ='jdoe'=, or undef if not 866matched. 867 868Note that it is possible for several login names to map to the same wikiname. 869This function will only return the *first* login name that maps to the 870wikiname. 871 872Returns undef if the WikiName is not found. 873 874To get the login name of the currently logged in user use: 875<verbatim> 876 my $user = TWiki::Func::wikiToUserName( TWiki::Func::getWikiName() ); 877</verbatim> 878 879*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 880 881=cut 882 883sub wikiToUserName { 884 my( $wiki ) = @_; 885 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 886 return '' unless $wiki; 887 888 my $cUID = getCanonicalUserID($wiki); 889 if ($cUID) { 890 my $login = $TWiki::Plugins::SESSION->{users}->getLoginName($cUID); 891 return undef if !$login || $login eq 'unknown'; 892 return $login; 893 } 894 return undef; 895} 896 897=pod 898 899#UserToWikiName 900---+++ userToWikiName( $loginName, $dontAddWeb ) -> $wikiName 901Translate a login name to a Wiki name 902 * =$loginName= - Login name, e.g. ='jdoe'=. Since TWiki 4.2.1 this may 903 also be a wiki name. This will normally be transparent, but may be 904 relevant if you have login names that are also valid wiki names. 905 * =$dontAddWeb= - Do not add web prefix if ="1"= 906 907Return: =$wikiName= Wiki name of user, e.g. ='Main.JohnDoe'= or ='JohnDoe'= 908 909userToWikiName will always return a name. If the user does not 910exist in the mapping, the $loginName parameter is returned. (backward compatibility) 911 912*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 913 914=cut 915 916sub userToWikiName { 917 my( $login, $dontAddWeb ) = @_; 918 return '' unless $login; 919 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 920 my $users = $TWiki::Plugins::SESSION->{users}; 921 my $user = getCanonicalUserID( $login ); 922 return ( $dontAddWeb ? $login : 923 ( $TWiki::cfg{UsersWebName} . '.' . $login ) ) 924 unless $users->userExists( $user ); 925 return $users->getWikiName( $user ) if $dontAddWeb; 926 return $users->webDotWikiName($user); 927} 928 929=pod 930 931#EmailToWikiNames 932---+++ emailToWikiNames( $email, $dontAddWeb ) -> @wikiNames 933 * =$email= - email address to look up 934 * =$dontAddWeb= - Do not add web prefix if ="1"= 935 936Find the wikinames of all users who have the given email address as their 937registered address. Since several users could register with the same email 938address, this returns a list of wikinames rather than a single wikiname. 939 940*Since:* TWiki::Plugins::VERSION 1.2 941 942=cut 943 944sub emailToWikiNames { 945 my( $email, $dontAddWeb ) = @_; 946 ASSERT($email) if DEBUG; 947 948 my %matches; 949 my $users = $TWiki::Plugins::SESSION->{users}; 950 my $ua = $users->findUserByEmail( $email ); 951 if ($ua) { 952 foreach my $user (@$ua) { 953 if( $dontAddWeb ) { 954 $matches{$users->getWikiName($user)} = 1; 955 } else { 956 $matches{$users->webDotWikiName($user)} = 1; 957 } 958 } 959 } 960 961 return sort keys %matches; 962} 963 964=pod 965 966#WikinameToEmails 967---+++ wikinameToEmails( $user ) -> @emails 968 * =$user= - wikiname of user to look up 969 970Returns the registered email addresses of the named user. If $user is 971undef, returns the registered email addresses for the logged-in user. 972 973Since TWiki 4.2.1, $user may also be a login name, or the name of a group. 974 975*Since:* TWiki::Plugins::VERSION 1.2 976 977=cut 978 979sub wikinameToEmails { 980 my( $wikiname ) = @_; 981 if( $wikiname ) { 982 if (isGroup($wikiname)) { 983 return $TWiki::Plugins::SESSION->{users}->getEmails( $wikiname ); 984 } else { 985 my $uids = $TWiki::Plugins::SESSION->{users}->findUserByWikiName( 986 $wikiname ); 987 my @em = (); 988 foreach my $user (@$uids) { 989 push(@em, $TWiki::Plugins::SESSION->{users}->getEmails( $user )); 990 } 991 return @em; 992 } 993 } else { 994 my $user = $TWiki::Plugins::SESSION->{user}; 995 return $TWiki::Plugins::SESSION->{users}->getEmails( $user ); 996 } 997} 998 999=pod 1000 1001#IsGuest 1002---+++ isGuest( ) -> $boolean 1003 1004Test if logged in user is a guest (!TWikiGuest) 1005 1006*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 1007 1008=cut 1009 1010sub isGuest { 1011 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1012 return $TWiki::Plugins::SESSION->{user} eq 1013 $TWiki::Plugins::SESSION->{users}->getCanonicalUserID( 1014 $TWiki::cfg{DefaultUserLogin} ); 1015} 1016 1017=pod 1018 1019#IsAnAdmin 1020---+++ isAnAdmin( $user, $topic, $web ) -> $boolean 1021 1022Find out if the user is an admin or not. If the user is not given, 1023the currently logged-in user is assumed. 1024 * $user can be either a login name or a WikiName 1025 * a user mapping handler's isAdmin() may take $topic and $web arguments. 1026 That's why this function takes them too. For a user mapping handler 1027 whose isAdmin() doesn't care $topic and $web (e.g. !TWikiUserMapping), 1028 $topic and $web are irrelevant, needless to say. 1029 1030*Since:* TWiki::Plugins::VERSION 1.2 1031 1032__Note:__ The parameters $topic and $web were added in 1033TWiki::Plugins::VERSION 6.00 1034 1035=cut 1036 1037sub isAnAdmin { 1038 #my ($user, $topic, $web) = @_ 1039 return $TWiki::Plugins::SESSION->{users}->isAdmin( 1040 getCanonicalUserID( $_[0] ), $_[1], $_[2]); 1041} 1042 1043=pod 1044 1045#IsGroupMember 1046---+++ isGroupMember( $group, $id ) -> $boolean 1047 1048Find out if $id is in the named group. e.g. 1049<verbatim> 1050if( TWiki::Func::isGroupMember( "HesperionXXGroup", "jordi" )) { 1051 ... 1052} 1053</verbatim> 1054If =$user= is =undef=, it defaults to the currently logged-in user. 1055 1056 * $id can be a login name or a WikiName 1057 1058*Since:* TWiki::Plugins::VERSION 1.2 1059 1060=cut 1061 1062sub isGroupMember { 1063 my ($group, $user) = @_; 1064 my $users = $TWiki::Plugins::SESSION->{users}; 1065 1066 return () unless $users->isGroup($group); 1067 if( $user ) { 1068 #my $login = wikiToUserName( $user ); 1069 #return 0 unless $login; 1070 $user = getCanonicalUserID( $user ); 1071 } else { 1072 $user = $TWiki::Plugins::SESSION->{user}; 1073 } 1074 return $users->isInGroup( $user, $group ); 1075} 1076 1077=pod 1078 1079#EachUser 1080---+++ eachUser() -> $iterator 1081Get an iterator over the list of all the registered users *not* including 1082groups. The iterator will return each wiki name in turn (e.g. 'FredBloggs'). 1083 1084Use it as follows: 1085<verbatim> 1086 my $iterator = TWiki::Func::eachUser(); 1087 while ($it->hasNext()) { 1088 my $user = $it->next(); 1089 # $user is a wikiname 1090 } 1091</verbatim> 1092 1093*WARNING* on large sites, this could be a long list! 1094 1095*Since:* TWiki::Plugins::VERSION 1.2 1096 1097=cut 1098 1099sub eachUser { 1100 my $it = $TWiki::Plugins::SESSION->{users}->eachUser(); 1101 $it->{process} = sub { 1102 return $TWiki::Plugins::SESSION->{users}->getWikiName( $_[0] ); 1103 }; 1104 return $it; 1105} 1106 1107=pod 1108 1109#EachMembership 1110---+++ eachMembership($id) -> $iterator 1111 * =$id= - WikiName or login name of the user. 1112 If =$id= is =undef=, defaults to the currently logged-in user. 1113Get an iterator over the names of all groups that the user is a member of. 1114 1115*Since:* TWiki::Plugins::VERSION 1.2 1116 1117=cut 1118 1119sub eachMembership { 1120 my ($user) = @_; 1121 my $users = $TWiki::Plugins::SESSION->{users}; 1122 1123 if( $user ) { 1124 my $login = wikiToUserName( $user ); 1125 return 0 unless $login; 1126 $user = getCanonicalUserID( $login ); 1127 } else { 1128 $user = $TWiki::Plugins::SESSION->{user}; 1129 } 1130 1131 return $users->eachMembership($user); 1132} 1133 1134=pod 1135 1136#EachGroup 1137---+++ eachGroup() -> $iterator 1138Get an iterator over all groups. 1139 1140Use it as follows: 1141<verbatim> 1142 my $iterator = TWiki::Func::eachGroup(); 1143 while ($it->hasNext()) { 1144 my $group = $it->next(); 1145 # $group is a group name e.g. TWikiAdminGroup 1146 } 1147</verbatim> 1148 1149*WARNING* on large sites, this could be a long list! 1150 1151*Since:* TWiki::Plugins::VERSION 1.2 1152 1153=cut 1154 1155sub eachGroup { 1156 my $session = $TWiki::Plugins::SESSION; 1157 my $it = $session->{users}->eachGroup(); 1158 return $it; 1159} 1160 1161=pod 1162 1163#IsGroup 1164---+++ isGroup( $group ) -> $boolean 1165 1166Checks if =$group= is the name of a group known to TWiki. 1167 1168=cut 1169 1170sub isGroup { 1171 my( $group ) = @_; 1172 1173 return $TWiki::Plugins::SESSION->{users}->isGroup( $group ); 1174} 1175 1176=pod 1177 1178#EachGroupMember 1179---+++ eachGroupMember($group) -> $iterator 1180Get an iterator over all the members of the named group. Returns undef if 1181$group is not a valid group. 1182 1183Use it as follows: 1184<verbatim> 1185 my $iterator = TWiki::Func::eachGroupMember('RadioheadGroup'); 1186 while ($it->hasNext()) { 1187 my $user = $it->next(); 1188 # $user is a wiki name e.g. 'TomYorke', 'PhilSelway' 1189 } 1190</verbatim> 1191 1192*WARNING* on large sites, this could be a long list! 1193 1194*Since:* TWiki::Plugins::VERSION 1.2 1195 1196=cut 1197 1198sub eachGroupMember { 1199 my $user = shift; 1200 my $session = $TWiki::Plugins::SESSION; 1201 return undef unless 1202 $TWiki::Plugins::SESSION->{users}->isGroup($user); 1203 my $it = $TWiki::Plugins::SESSION->{users}->eachGroupMember($user); 1204 $it->{process} = sub { 1205 return $TWiki::Plugins::SESSION->{users}->getWikiName( $_[0] ); 1206 }; 1207 return $it; 1208} 1209 1210=pod 1211 1212#CheckAccessPermission 1213---+++ checkAccessPermission( $type, $id, $text, $topic, $web, $meta ) -> $boolean 1214 1215Check access permission for a topic based on the 1216[[%SYSTEMWEB%.TWikiAccessControl]] rules 1217 * =$type= - Access type, required, e.g. ='VIEW'=, ='CHANGE'=. 1218 * =$id= - WikiName of remote user, required, e.g. ="PeterThoeny"=. From 1219 TWiki 4.2.1, $id may also be a login name. 1220 If =$id= is '', 0 or =undef= then access is *always permitted*. 1221 * =$text= - Topic text, optional. If 'perl false' (undef, 0 or ''), 1222 topic =$web.$topic= is consulted. =$text= may optionally contain embedded 1223 =%META:PREFERENCE= tags. Provide this parameter if: 1224 1 You are setting different access controls in the text to those defined 1225 in the stored topic, 1226 1 You already have the topic text in hand, and want to help TWiki avoid 1227 having to read it again, 1228 1 You are providing a =$meta= parameter. 1229 * =$topic= - Topic name, required, e.g. ='PrivateStuff'= 1230 * =$web= - Web name, required, e.g. ='Sandbox'= 1231 * =$meta= - Meta-data object, as returned by =readTopic=. Optional. 1232 If =undef=, but =$text= is defined, then access controls will be parsed 1233 from =$text=. If defined, then metadata embedded in =$text= will be 1234 ignored. This parameter is always ignored if =$text= is undefined. 1235 Settings in =$meta= override =Set= settings in $text. 1236A perl true result indicates that access is permitted. 1237 1238*Note* the weird parameter order is due to compatibility constraints with 1239earlier TWiki releases. 1240 1241*Tip* if you want, you can use this method to check your own access control types. For example, if you: 1242 * Set ALLOWTOPICSPIN = !IncyWincy 1243in =ThatWeb.ThisTopic=, then a call to =checkAccessPermission('SPIN', 'IncyWincy', undef, 'ThisTopic', 'ThatWeb', undef)= will return =true=. 1244 1245*Since:* TWiki::Plugins::VERSION 1.000 (27 Feb 2001) 1246 1247=cut 1248 1249sub checkAccessPermission { 1250 my( $type, $user, $text, $topic, $web, $meta ) = @_; 1251 return 1 unless ( $user ); 1252 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1253 $text = undef unless $text; 1254 my $cUID = getCanonicalUserID($user) || 1255 getCanonicalUserID($TWiki::cfg{DefaultUserLogin}); 1256 return $TWiki::Plugins::SESSION->security->checkAccessPermission( 1257 $type, $cUID, $text, $meta, $topic, $web ); 1258} 1259 1260=pod 1261 1262#WebsTopicsAndAttachmentsFunctions 1263---++ Webs, Topics and Attachments 1264 1265=cut 1266 1267=pod 1268 1269#GetListOfWebs 1270---+++ getListOfWebs( $filter ) -> @webs 1271 1272 * =$filter= - spec of web types to recover 1273Gets a list of webs, filtered according to the spec in the $filter, 1274which may include one of: 1275 1 'user' (for only user webs) 1276 2 'template' (for only template webs i.e. those starting with "_") 1277=$filter= may also contain the word 'public' which will further filter 1278out webs that have NOSEARCHALL set on them. 1279'allowed' filters out webs the current user can't read. 1280 1281For example, the deprecated getPublicWebList function can be duplicated 1282as follows: 1283<verbatim> 1284 my @webs = TWiki::Func::getListOfWebs( "user,public" ); 1285</verbatim> 1286 1287*Since:* TWiki::Plugins::VERSION 1.1 1288 1289=cut 1290 1291sub getListOfWebs { 1292 my $filter = shift; 1293 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1294 return $TWiki::Plugins::SESSION->{store}->getListOfWebs($filter); 1295} 1296 1297=pod 1298 1299#WebExists 1300---+++ webExists( $web ) -> $boolean 1301 1302Test if web exists 1303 * =$web= - Web name, required, e.g. ='Sandbox'= 1304 1305*Since:* TWiki::Plugins::VERSION 1.000 (14 Jul 2001) 1306 1307=cut 1308 1309sub webExists { 1310# my( $web ) = @_; 1311 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1312 return $TWiki::Plugins::SESSION->{store}->webExists( @_ ); 1313} 1314 1315=pod 1316 1317---+++ isValidWebName( $name, $templateWeb ) -> $boolean 1318 1319Check for a valid web name. 1320 * =$name= - web name 1321 * =$templateWeb= - flag, optional. If true, then template web names (starting with _) 1322 are considered valid, otherwise only user web names are valid. 1323Return: true if web name is valid 1324 1325If $TWiki::cfg{EnableHierarchicalWebs} is off, it will also return false when a nested 1326web name is passed to it. 1327 1328*Since:* TWiki::Plugins::VERSION 1.4 1329 1330=cut 1331 1332sub isValidWebName { 1333 return TWiki::isValidWebName( @_ ); 1334} 1335 1336=pod 1337 1338#CreateWeb 1339---+++ createWeb( $newWeb, $baseWeb, $opts ) 1340 1341 * =$newWeb= is the name of the new web. 1342 * =$baseWeb= is the name of an existing web (a template web). If the base web is a system web, all topics in it will be copied into the new web. If it is a normal web, only topics starting with 'Web' will be copied. If no base web is specified, an empty web (with no topics) will be created. If it is specified but does not exist, an error will be thrown. 1343 * =$opts= is a ref to a hash that contains settings to be modified in 1344the web preferences topic in the new web. 1345 1346<verbatim> 1347use Error qw( :try ); 1348use TWiki::AccessControlException; 1349 1350try { 1351 TWiki::Func::createWeb( "Newweb" ); 1352} catch Error::Simple with { 1353 my $e = shift; 1354 # see documentation on Error::Simple 1355} catch TWiki::AccessControlException with { 1356 my $e = shift; 1357 # see documentation on TWiki::AccessControlException 1358} otherwise { 1359 ... 1360}; 1361</verbatim> 1362 1363*Since:* TWiki::Plugins::VERSION 1.1 1364 1365=cut 1366 1367sub createWeb { 1368 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1369 $TWiki::Plugins::SESSION->{store}->createWeb( 1370 $TWiki::Plugins::SESSION->{user}, @_ ); 1371} 1372 1373=pod 1374 1375#MoveWeb 1376---+++ moveWeb( $oldName, $newName ) 1377 1378Move (rename) a web. 1379 1380<verbatim> 1381use Error qw( :try ); 1382use TWiki::AccessControlException; 1383 1384try { 1385 TWiki::Func::moveWeb( "Oldweb", "Newweb" ); 1386} catch Error::Simple with { 1387 my $e = shift; 1388 # see documentation on Error::Simple 1389} catch TWiki::AccessControlException with { 1390 my $e = shift; 1391 # see documentation on TWiki::AccessControlException 1392} otherwise { 1393 ... 1394}; 1395</verbatim> 1396 1397To delete a web, move it to a subweb of =Trash= 1398<verbatim> 1399TWiki::Func::moveWeb( "Deadweb", "Trash.Deadweb" ); 1400</verbatim> 1401 1402*Since:* TWiki::Plugins::VERSION 1.1 1403 1404=cut 1405 1406sub moveWeb { 1407 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1408 return $TWiki::Plugins::SESSION->{store}->moveWeb( 1409 @_, $TWiki::Plugins::SESSION->{user}); 1410 1411} 1412 1413=pod 1414 1415#EachChangeSince 1416---+++ eachChangeSince($web, $time) -> $iterator 1417 1418Get an iterator over the list of all the changes in the given web between 1419=$time= and now. $time is a time in seconds since 1st Jan 1970, and is not 1420guaranteed to return any changes that occurred before (now - 1421{Store}{RememberChangesFor}). {Store}{RememberChangesFor}) is a 1422setting in =configure=. Changes are returned in *most-recent-first* 1423order. 1424 1425Use it as follows: 1426<verbatim> 1427 my $iterator = TWiki::Func::eachChangeSince( 1428 $web, time() - 7 * 24 * 60 * 60); # the last 7 days 1429 while ($iterator->hasNext()) { 1430 my $change = $iterator->next(); 1431 # $change is a perl hash that contains the following fields: 1432 # topic => topic name 1433 # user => wikiname - wikiname of user who made the change 1434 # time => time of the change 1435 # revision => revision number *after* the change 1436 # more => more info about the change (e.g. 'minor') 1437 } 1438</verbatim> 1439 1440*Since:* TWiki::Plugins::VERSION 1.2 1441 1442=cut 1443 1444sub eachChangeSince { 1445 my( $web, $time ) = @_; 1446 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1447 ASSERT($TWiki::Plugins::SESSION->{store}->webExists($web)) if DEBUG; 1448 1449 my $iterator = 1450 $TWiki::Plugins::SESSION->{store}->eachChange( $web, $time ); 1451 return $iterator; 1452} 1453 1454=pod 1455 1456#GetTopicList 1457---+++ getTopicList( $web ) -> @topics 1458 1459Get list of all topics in a web 1460 * =$web= - Web name, required, e.g. ='Sandbox'= 1461Return: =@topics= Topic list, e.g. =( 'WebChanges', 'WebHome', 'WebIndex', 'WebNotify' )= 1462 1463*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 1464 1465=cut 1466 1467sub getTopicList { 1468# my( $web ) = @_; 1469 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1470 return $TWiki::Plugins::SESSION->{store}->getTopicNames ( @_ ); 1471} 1472 1473=pod 1474 1475#TopicExists 1476---+++ topicExists( $web, $topic ) -> $boolean 1477 1478Test if topic exists. 1479 * =$web= - Web name, optional, e.g. ='Main'=. 1480 * =$topic= - Topic name, required, e.g. ='TokyoOffice'=, or ="Main.TokyoOffice"= 1481 1482$web and $topic are parsed as described in the documentation for =normalizeWebTopicName=. 1483Specifically, the %USERSWEB% is used if $web is not specified and $topic has no web specifier. 1484To get an expected behaviour it is recommened to specify the current web for $web; don't leave it empty. 1485 1486*Since:* TWiki::Plugins::VERSION 1.000 (14 Jul 2001) 1487 1488=cut 1489 1490sub topicExists { 1491 my( $web, $topic ) = $TWiki::Plugins::SESSION->normalizeWebTopicName( @_ ); 1492 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1493 return $TWiki::Plugins::SESSION->{store}->topicExists( $web, $topic ); 1494} 1495 1496=pod 1497 1498---+++ isValidTopicName( $name ) -> $boolean 1499 1500Check for a valid topic name. Names considerd valid for autolinking are 1501%SYSTEMWEB%.WikiWords (such as 'SanFrancisco') and acronym (such as 'SWMBO'). 1502 * =$name= - topic name 1503Return: true if topic name is valid 1504 1505*Since:* TWiki::Plugins::VERSION 1.4 1506 1507=cut 1508 1509sub isValidTopicName { 1510 return TWiki::isValidTopicName( @_ ); 1511} 1512 1513=pod 1514 1515#CheckTopicEditLock 1516---+++ checkTopicEditLock( $web, $topic, $script ) -> ( $oopsUrl, $loginName, $unlockTime ) 1517 1518Check if a lease has been taken by some other user. 1519 * =$web= Web name, e.g. ="Main"=, or empty 1520 * =$topic= Topic name, e.g. ="MyTopic"=, or ="Main.MyTopic"= 1521Return: =( $oopsUrl, $loginName, $unlockTime )= - The =$oopsUrl= for calling redirectCgiQuery(), user's =$loginName=, and estimated =$unlockTime= in minutes, or ( '', '', 0 ) if no lease exists. 1522 * =$script= The script to invoke when continuing with the edit 1523 1524*Since:* TWiki::Plugins::VERSION 1.010 (31 Dec 2002) 1525 1526=cut 1527 1528sub checkTopicEditLock { 1529 my( $web, $topic, $script ) = @_; 1530 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1531 1532 ( $web, $topic ) = normalizeWebTopicName( $web, $topic ); 1533 $script ||= 'edit'; 1534 1535 my $lease = $TWiki::Plugins::SESSION->{store}->getLease( $web, $topic ); 1536 if( $lease ) { 1537 my $remain = $lease->{expires} - time(); 1538 my $session = $TWiki::Plugins::SESSION; 1539 1540 if( $remain > 0 ) { 1541 my $who = $lease->{user}; 1542 require TWiki::Time; 1543 my $past = TWiki::Time::formatDelta( 1544 time()-$lease->{taken}, 1545 $TWiki::Plugins::SESSION->i18n 1546 ); 1547 my $future = TWiki::Time::formatDelta( 1548 $lease->{expires}-time(), 1549 $TWiki::Plugins::SESSION->i18n 1550 ); 1551 my $url = getScriptUrl( 1552 $web, $topic, 'oops', 1553 template => 'oopsleaseconflict', 1554 def => 'lease_active', 1555 param1 => $who, 1556 param2 => $past, 1557 param3 => $future, 1558 param4 => $script ); 1559 my $login = $session->{users}->getLoginName($who); 1560 return( $url, $login, $remain / 60 ); 1561 } 1562 } 1563 return ('', '', 0); 1564} 1565 1566=pod 1567 1568#SetTopicEditLock 1569---+++ setTopicEditLock( $web, $topic, $lock ) 1570 1571 * =$web= Web name, e.g. ="Main"=, or empty 1572 * =$topic= Topic name, e.g. ="MyTopic"=, or ="Main.MyTopic"= 1573 * =$lock= 1 to lease the topic, 0 to clear an existing lease 1574 1575Takes out a "lease" on the topic. The lease doesn't prevent 1576anyone from editing and changing the topic, but it does redirect them 1577to a warning screen, so this provides some protection. The =edit= script 1578always takes out a lease. 1579 1580It is *impossible* to fully lock a topic. Concurrent changes will be 1581merged. 1582 1583*Since:* TWiki::Plugins::VERSION 1.010 (31 Dec 2002) 1584 1585=cut 1586 1587sub setTopicEditLock { 1588 my( $web, $topic, $lock ) = @_; 1589 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1590 my $session = $TWiki::Plugins::SESSION; 1591 my $store = $session->{store}; 1592 if( $lock ) { 1593 $store->setLease( $web, $topic, $session->{user}, 1594 $TWiki::cfg{LeaseLength} ); 1595 } else { 1596 $store->clearLease( $web, $topic ); 1597 } 1598 return ''; 1599} 1600 1601=pod 1602 1603#SaveTopic 1604---+++ saveTopic( $web, $topic, $meta, $text, $options ) -> $error 1605 1606 * =$web= - web for the topic 1607 * =$topic= - topic name 1608 * =$meta= - reference to TWiki::Meta object 1609 * =$text= - text of the topic (without embedded meta-data!!! 1610 * =\%options= - ref to hash of save options 1611 =\%options= may include: 1612 | =dontlog= | don't log this change in twiki log | 1613 | =forcenewrevision= | force the save to increment the revision counter | 1614 | =minor= | True if this is a minor change, and is not to be notified | 1615Return: error message or undef. 1616 1617*Since:* TWiki::Plugins::VERSION 1.000 (29 Jul 2001) 1618 1619Example: 1620<verbatim> 1621 # read topic: 1622 my( $topicMeta, $topicText ) = TWiki::Func::readTopic( $web, $topic ); 1623 # example to change topic text: 1624 $topicText =~ s/APPLE/ORANGE/g; 1625 # example to change TWiki form field: 1626 my $field = $topicMeta->get( 'FIELD', 'Title' ); 1627 if( $field ) { 1628 $field->{value} = $newTitle; 1629 $topicMeta->putKeyed( 'FIELD', $field ); 1630 } 1631 # save updated topic: 1632 TWiki::Func::saveTopic( $web, $topic, $topicMeta, $topicText, { forcenewrevision => 1 } ); 1633</verbatim> 1634 1635__Note:__ Plugins handlers ( e.g. =beforeSaveHandler= ) will be called as 1636appropriate. 1637 1638=cut 1639 1640sub saveTopic { 1641 my( $web, $topic, $meta, $text, $options ) = @_; 1642 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1643 1644 return $TWiki::Plugins::SESSION->{store}->saveTopic 1645 ( $TWiki::Plugins::SESSION->{user}, $web, $topic, $text, $meta, 1646 $options ); 1647 1648} 1649 1650=pod 1651 1652#SaveTopicText 1653---+++ saveTopicText( $web, $topic, $text, $ignorePermissions, $dontNotify ) -> $oopsUrl 1654 1655Save topic text, typically obtained by readTopicText(). Topic data usually includes meta data; the file attachment meta data is replaced by the meta data from the topic file if it exists. 1656 * =$web= - Web name, e.g. ='Main'=, or empty 1657 * =$topic= - Topic name, e.g. ='MyTopic'=, or ="Main.MyTopic"= 1658 * =$text= - Topic text to save, assumed to include meta data 1659 * =$ignorePermissions= - Set to ="1"= if checkAccessPermission() is already performed and OK 1660 * =$dontNotify= - Set to ="1"= if not to notify users of the change 1661Return: =$oopsUrl= Empty string if OK; the =$oopsUrl= for calling redirectCgiQuery() in case of error 1662 1663This method is a lot less efficient and much more dangerous than =saveTopic=. 1664 1665*Since:* TWiki::Plugins::VERSION 1.010 (31 Dec 2002) 1666 1667<verbatim> 1668my $text = TWiki::Func::readTopicText( $web, $topic ); 1669 1670# check for oops URL in case of error: 1671if( $text =~ /^http.*?\/oops/ ) { 1672 TWiki::Func::redirectCgiQuery( $query, $text ); 1673 return; 1674} 1675# do topic text manipulation like: 1676$text =~ s/old/new/g; 1677# do meta data manipulation like: 1678$text =~ s/(META\:FIELD.*?name\=\"TopicClassification\".*?value\=\")[^\"]*/$1BugResolved/; 1679$oopsUrl = TWiki::Func::saveTopicText( $web, $topic, $text ); # save topic text 1680</verbatim> 1681 1682=cut 1683 1684sub saveTopicText { 1685 my( $web, $topic, $text, $ignorePermissions, $dontNotify ) = @_; 1686 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1687 1688 my $session = $TWiki::Plugins::SESSION; 1689 TWiki::UI::checkWebWritable($session, $web); 1690 1691 # check access permission 1692 unless( $ignorePermissions || 1693 $session->security->checkAccessPermission( 1694 'CHANGE', $session->{user}, undef, undef, 1695 $topic, $web ) 1696 ) { 1697 my @plugin = caller(); 1698 return getScriptUrl( 1699 $web, $topic, 'oops', 1700 template => 'oopsaccessdenied', 1701 def => 'topic_access', 1702 param1 => 'in', 1703 param2 => $plugin[0] ); 1704 } 1705 1706 return getScriptUrl( 1707 $web, $topic, 'oops', template => 'oopsattention', def => 'save_error', 1708 param1 => 'No text' ) 1709 unless( defined $text ); 1710 1711 # extract meta data and merge old attachment meta data 1712 require TWiki::Meta; 1713 my $meta = new TWiki::Meta( $session, $web, $topic, $text ); 1714 1715 $meta->remove( 'FILEATTACHMENT' ); 1716 1717 my( $oldMeta, $oldText ) = 1718 $session->{store}->readTopic( undef, $web, $topic, undef ); 1719 $meta->copyFrom( $oldMeta, 'FILEATTACHMENT' ); 1720 # save topic 1721 my $error = 1722 $session->{store}->saveTopic 1723 ( $session->{user}, $web, $topic, $meta->text(), $meta, 1724 { notify => $dontNotify, ignorePermissions => $ignorePermissions } ); 1725 return getScriptUrl( 1726 $web, $topic, 'oops', template => 'oopsattention', def => 'save_error', 1727 param1 => $error ) if( $error ); 1728 return ''; 1729} 1730 1731=pod 1732 1733#MoveTopic 1734---+++ moveTopic( $web, $topic, $newWeb, $newTopic ) 1735 1736 * =$web= source web - required 1737 * =$topic= source topic - required 1738 * =$newWeb= dest web 1739 * =$newTopic= dest topic 1740Renames the topic. Throws an exception if something went wrong. 1741If $newWeb is undef, it defaults to $web. If $newTopic is undef, it defaults 1742to $topic. 1743 1744The destination topic must not already exist. 1745 1746Rename a topic to the $TWiki::cfg{TrashWebName} to delete it. 1747 1748*Since:* TWiki::Plugins::VERSION 1.1 1749 1750<verbatim> 1751use Error qw( :try ); 1752 1753try { 1754 moveTopic( "Work", "TokyoOffice", "Trash", "ClosedOffice" ); 1755} catch Error::Simple with { 1756 my $e = shift; 1757 # see documentation on Error::Simple 1758} catch TWiki::AccessControlException with { 1759 my $e = shift; 1760 # see documentation on TWiki::AccessControlException 1761} otherwise { 1762 ... 1763}; 1764</verbatim> 1765 1766=cut 1767 1768sub moveTopic { 1769 my( $web, $topic, $newWeb, $newTopic ) = @_; 1770 $newWeb ||= $web; 1771 $newTopic ||= $topic; 1772 1773 return if( $newWeb eq $web && $newTopic eq $topic ); 1774 1775 $TWiki::Plugins::SESSION->{store}->moveTopic( 1776 $web, $topic, 1777 $newWeb, $newTopic, 1778 $TWiki::Plugins::SESSION->{user} ); 1779} 1780 1781=pod 1782 1783#GetRevisionInfo 1784---+++ getRevisionInfo($web, $topic, $rev, $attachment ) -> ( $date, $user, $rev, $comment ) 1785 1786Get revision info of a topic or attachment 1787 * =$web= - Web name, optional, e.g. ='Main'= 1788 * =$topic= - Topic name, required, e.g. ='TokyoOffice'= 1789 * =$rev= - revsion number, or tag name (can be in the format 1.2, or just the minor number) 1790 * =$attachment= -attachment filename 1791Return: =( $date, $user, $rev, $comment )= List with: ( last update date, login name of last user, minor part of top revision number ), e.g. =( 1234561, 'phoeny', "5" )= 1792| $date | in epochSec | 1793| $user | Wiki name of the author (*not* login name) | 1794| $rev | actual rev number | 1795| $comment | WHAT COMMENT? | 1796 1797NOTE: if you are trying to get revision info for a topic, use 1798=$meta->getRevisionInfo= instead if you can - it is significantly 1799more efficient. 1800 1801*Since:* TWiki::Plugins::VERSION 1.000 (29 Jul 2001) 1802 1803=cut 1804 1805sub getRevisionInfo { 1806 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1807 my( $date, $user, $rev, $comment ); 1808 if ( $_[3] ) { 1809 # attachment specified 1810 ( $date, $user, $rev, $comment ) = 1811 $TWiki::Plugins::SESSION->{store}->getRevisionInfo( @_ ); 1812 $user = getWikiName( $user ); 1813 # Item7238: you must not use TWiki::Users::getWikiName() here 1814 # because it assumes a cUID and causes problems if a wikiname is 1815 # handed. 1816 } 1817 else { 1818 my $revInfo = 1819 $TWiki::Plugins::SESSION->renderer->renderRevisionInfo( 1820 $_[0], $_[1], undef, $_[2], '$epoch|$wikiname|$rev|$comment' ); 1821 ( $date, $user, $rev, $comment ) = split(/\|/, $revInfo, 4); 1822 } 1823 return ( $date, $user, $rev, $comment ); 1824} 1825 1826=pod 1827 1828#GetRevisionAtTime 1829---+++ getRevisionAtTime( $web, $topic, $time ) -> $rev 1830 1831Get the revision number of a topic at a specific time. 1832 * =$web= - web for topic 1833 * =$topic= - topic 1834 * =$time= - time (in epoch secs) for the rev 1835Return: Single-digit revision number, or undef if it couldn't be determined 1836(either because the topic isn't that old, or there was a problem) 1837 1838*Since:* TWiki::Plugins::VERSION 1.1 1839 1840=cut 1841 1842sub getRevisionAtTime { 1843 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1844 return $TWiki::Plugins::SESSION->{store}->getRevisionAtTime( @_ ); 1845} 1846 1847=pod 1848 1849#ReadTopic 1850---+++ readTopic( $web, $topic, $rev ) -> ( $meta, $text ) 1851 1852Read topic text and meta data, regardless of access permissions. 1853 * =$web= - Web name, required, e.g. ='Main'= 1854 * =$topic= - Topic name, required, e.g. ='TokyoOffice'= 1855 * =$rev= - revision to read (default latest) 1856Return: =( $meta, $text )= Meta data object and topic text 1857 1858=$meta= is a perl 'object' of class =TWiki::Meta=. This class is 1859fully documented in the source code documentation shipped with the 1860release, or can be inspected in the =lib/TWiki/Meta.pm= file. 1861 1862This method *ignores* topic access permissions. You should be careful to use 1863=checkAccessPermission= to ensure the current user has read access to the 1864topic. 1865 1866See usage example at [[#SaveTopic][TWiki::Func::saveTopic]]. 1867 1868*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 1869 1870=cut 1871 1872sub readTopic { 1873 #my( $web, $topic, $rev ) = @_; 1874 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1875 1876 return $TWiki::Plugins::SESSION->{store}->readTopic( undef, @_ ); 1877} 1878 1879=pod 1880 1881#ReadTopicText 1882---+++ readTopicText( $web, $topic, $rev, $ignorePermissions ) -> $text 1883 1884Read topic text, including meta data 1885 * =$web= - Web name, e.g. ='Main'=, or empty 1886 * =$topic= - Topic name, e.g. ='MyTopic'=, or ="Main.MyTopic"= 1887 * =$rev= - Topic revision to read, optional. Specify the minor part of the revision, e.g. ="5"=, not ="1.5"=; the top revision is returned if omitted or empty. 1888 * =$ignorePermissions= - Set to ="1"= if checkAccessPermission() is already performed and OK; an oops URL is returned if user has no permission 1889Return: =$text= Topic text with embedded meta data; an oops URL for calling redirectCgiQuery() is returned in case of an error 1890 1891This method is more efficient than =readTopic=, but returns meta-data embedded in the text. Plugins authors must be very careful to avoid damaging meta-data. You are recommended to use readTopic instead, which is a lot safer. 1892 1893*Since:* TWiki::Plugins::VERSION 1.010 (31 Dec 2002) 1894 1895=cut 1896 1897sub readTopicText { 1898 my( $web, $topic, $rev, $ignorePermissions ) = @_; 1899 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1900 1901 my $user; 1902 $user = $TWiki::Plugins::SESSION->{user} 1903 unless defined( $ignorePermissions ); 1904 1905 my $text; 1906 try { 1907 $text = 1908 $TWiki::Plugins::SESSION->{store}->readTopicRaw 1909 ( $user, $web, $topic, $rev ); 1910 } catch TWiki::AccessControlException with { 1911 my $e = shift; 1912 $text = getScriptUrl( 1913 $web, $topic, 'oops', 1914 template => 'oopsaccessdenied', def=>'topic_access', 1915 param1 => $e->{mode}, 1916 param2 => $e->{reason} ); 1917 }; 1918 1919 return $text; 1920} 1921 1922=pod 1923 1924#AttachmentExists 1925---+++ attachmentExists( $web, $topic, $attachment ) -> $boolean 1926 1927Test if attachment exists 1928 * =$web= - Web name, optional, e.g. =Main=. 1929 * =$topic= - Topic name, required, e.g. =TokyoOffice=, or =Main.TokyoOffice= 1930 * =$attachment= - attachment name, e.g. =logo.gif= 1931$web and $topic are parsed as described in the documentation for =normalizeWebTopicName=. 1932 1933*Since:* TWiki::Plugins::VERSION 1.1 1934 1935=cut 1936 1937sub attachmentExists { 1938 my( $web, $topic, $attachment ) = @_; 1939 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1940 1941 ( $web, $topic ) = 1942 $TWiki::Plugins::SESSION->normalizeWebTopicName( $web, $topic ); 1943 return $TWiki::Plugins::SESSION->{store}->attachmentExists( 1944 $web, $topic, $attachment ); 1945} 1946 1947=pod 1948 1949#ReadAttachment 1950---+++ readAttachment( $web, $topic, $name, $rev ) -> $data 1951 1952 * =$web= - web for topic 1953 * =$topic= - topic 1954 * =$name= - attachment name 1955 * =$rev= - revision to read (default latest) 1956Read an attachment from the store for a topic, and return it as a string. The 1957names of attachments on a topic can be recovered from the meta-data returned 1958by =readTopic=. If the attachment does not exist, or cannot be read, undef 1959will be returned. If the revision is not specified, the latest version will 1960be returned. 1961 1962View permission on the topic is required for the 1963read to be successful. Access control violations are flagged by a 1964TWiki::AccessControlException. Permissions are checked for the current user. 1965 1966<verbatim> 1967my( $meta, $text ) = TWiki::Func::readTopic( $web, $topic ); 1968my @attachments = $meta->find( 'FILEATTACHMENT' ); 1969foreach my $a ( @attachments ) { 1970 try { 1971 my $data = TWiki::Func::readAttachment( $web, $topic, $a->{name} ); 1972 ... 1973 } catch TWiki::AccessControlException with { 1974 }; 1975} 1976</verbatim> 1977 1978*Since:* TWiki::Plugins::VERSION 1.1 1979 1980=cut 1981 1982sub readAttachment { 1983 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 1984 my $result; 1985 1986# try { 1987 $result = $TWiki::Plugins::SESSION->{store}->readAttachment( 1988 $TWiki::Plugins::SESSION->{user}, @_ ); 1989# } catch Error::Simple with { 1990# }; 1991 return $result; 1992} 1993 1994=pod 1995 1996#SaveAttachment 1997---+++ saveAttachment( $web, $topic, $attachment, $opts ) 1998 1999 * =$web= - web for topic 2000 * =$topic= - topic to atach to 2001 * =$attachment= - name of the attachment 2002 * =$opts= - Ref to hash of options 2003 * =$ignorePermissions= - Set to ="1"= if checkAccessPermission() is already performed and OK. 2004=$opts= may include: 2005| =dontlog= | don't log this change in twiki log | 2006| =comment= | comment for save | 2007| =hide= | if the attachment is to be hidden in normal topic view | 2008| =stream= | Stream of file to upload | 2009| =file= | Name of a file to use for the attachment data. ignored if stream is set. Local file on the server. | 2010| =filepath= | Client path to file | 2011| =filesize= | Size of uploaded data | 2012| =filedate= | Date | 2013 2014Save an attachment to the store for a topic. On success, returns undef. If there is an error, an exception will be thrown. 2015 2016<verbatim> 2017 try { 2018 TWiki::Func::saveAttachment( $web, $topic, 'image.gif', 2019 { file => 'image.gif', 2020 comment => 'Picture of Health', 2021 hide => 1 } ); 2022 } catch Error::Simple with { 2023 # see documentation on Error 2024 } otherwise { 2025 ... 2026 }; 2027</verbatim> 2028 2029*Since:* TWiki::Plugins::VERSION 1.1 2030 2031=cut 2032 2033sub saveAttachment { 2034 my( $web, $topic, $name, $data, $ignorePermissions ) = @_; 2035 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2036 my $result = undef; 2037 $data->{ignorePermissions} = $ignorePermissions || ''; 2038 2039 try { 2040 $TWiki::Plugins::SESSION->{store}->saveAttachment( 2041 $web, $topic, $name, 2042 $TWiki::Plugins::SESSION->{user}, 2043 $data ); 2044 } catch Error::Simple with { 2045 $result = shift->{-text}; 2046 }; 2047 2048 return $result; 2049} 2050 2051=pod 2052 2053#MoveAttachment 2054---+++ moveAttachment( $web, $topic, $attachment, $newWeb, $newTopic, $newAttachment ) 2055 2056 * =$web= source web - required 2057 * =$topic= source topic - required 2058 * =$attachment= source attachment - required 2059 * =$newWeb= dest web 2060 * =$newTopic= dest topic 2061 * =$newAttachment= dest attachment 2062Renames the topic. Throws an exception on error or access violation. 2063If $newWeb is undef, it defaults to $web. If $newTopic is undef, it defaults 2064to $topic. If $newAttachment is undef, it defaults to $attachment. If all of $newWeb, $newTopic and $newAttachment are undef, it is an error. 2065 2066The destination topic must already exist, but the destination attachment must 2067*not* exist. 2068 2069Rename an attachment to $TWiki::cfg{TrashWebName}.TrashAttament to delete it. 2070 2071<verbatim> 2072use Error qw( :try ); 2073 2074try { 2075 # move attachment between topics 2076 moveAttachment( "Countries", "Germany", "AlsaceLorraine.dat", 2077 "Countries", "France" ); 2078 # Note destination attachment name is defaulted to the same as source 2079} catch TWiki::AccessControlException with { 2080 my $e = shift; 2081 # see documentation on TWiki::AccessControlException 2082} catch Error::Simple with { 2083 my $e = shift; 2084 # see documentation on Error::Simple 2085}; 2086</verbatim> 2087 2088*Since:* TWiki::Plugins::VERSION 1.1 2089 2090=cut 2091 2092sub moveAttachment { 2093 my( $web, $topic, $attachment, $newWeb, $newTopic, $newAttachment ) = @_; 2094 2095 $newWeb ||= $web; 2096 $newTopic ||= $topic; 2097 $newAttachment ||= $attachment; 2098 2099 return if( $newWeb eq $web && 2100 $newTopic eq $topic && 2101 $newAttachment eq $attachment ); 2102 2103 $TWiki::Plugins::SESSION->{store}->moveAttachment( 2104 $web, $topic, $attachment, 2105 $newWeb, $newTopic, $newAttachment, 2106 $TWiki::Plugins::SESSION->{user} ); 2107} 2108 2109=pod 2110 2111#AssemblingPagesFunctions 2112---++ Assembling Pages 2113 2114=cut 2115 2116=pod 2117 2118#ReadTemplate 2119---+++ readTemplate( $name, $skin ) -> $text 2120 2121Read a template or skin. Embedded [[%SYSTEMWEB%.TWikiTemplates][template directives]] get expanded 2122 * =$name= - Template name, e.g. ='view'= 2123 * =$skin= - Comma-separated list of skin names, optional, e.g. ='print'= 2124Return: =$text= Template text 2125 2126*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 2127 2128=cut 2129 2130sub readTemplate { 2131# my( $name, $skin ) = @_; 2132 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2133 return $TWiki::Plugins::SESSION->templates->readTemplate( @_ ); 2134} 2135 2136=pod 2137 2138#LoadTemplate 2139---+++ loadTemplate ( $name, $skin, $web ) -> $text 2140 2141 * =$name= - template file name 2142 * =$skin= - comma-separated list of skins to use (default: current skin) 2143 * =$web= - the web to look in for topics that contain templates (default: current web) 2144Return: expanded template text (what's left after removal of all %<nop>TMPL:DEF% statements) 2145 2146*Since:* TWiki::Plugins::VERSION 1.1 2147 2148Reads a template and extracts template definitions, adding them to the 2149list of loaded templates, overwriting any previous definition. 2150 2151How TWiki searches for templates is described in TWikiTemplates. 2152 2153If template text is found, extracts include statements and fully expands them. 2154 2155=cut 2156 2157sub loadTemplate { 2158 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2159 return $TWiki::Plugins::SESSION->templates->readTemplate( @_ ); 2160} 2161 2162=pod 2163 2164#ExpandTemplate 2165---+++ expandTemplate( $def ) -> $string 2166 2167Do a %<nop>TMPL:P{$def}%, only expanding the template (not expanding any variables other than %TMPL) 2168 * =$def= - template name 2169Return: the text of the expanded template 2170 2171*Since:* TWiki::Plugins::VERSION 1.1 2172 2173A template is defined using a %<nop>TMPL:DEF% statement in a template 2174file. See the documentation on TWiki templates for more information. 2175 2176=cut 2177 2178sub expandTemplate { 2179 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2180 return $TWiki::Plugins::SESSION->templates->expandTemplate( @_ ); 2181} 2182 2183=pod 2184 2185#WriteHeader 2186---+++ writeHeader( ) 2187 2188Print a basic content-type HTML header for text/html to standard out. No return value. 2189 2190Note: In TWiki versions earlier than TWiki::Plugins::VERSION 1.3, this function used to have =$query= and =$contentLength= parameters. Both were marked "you should _not_ pass this parameter". 2191 2192*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 2193 2194=cut 2195 2196sub writeHeader { 2197 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2198 $TWiki::Plugins::SESSION->generateHTTPHeaders(); 2199} 2200 2201=pod 2202 2203#RedirectCgiQuery 2204---+++ redirectCgiQuery( $query, $url, $passthru, $viaCache ) 2205 2206Redirect to URL 2207 * =$query= - CGI query object. Ignored, only there for compatibility. The session CGI query object is used instead. 2208 * =$url= - URL to redirect to 2209 * =$passthru= - enable passthrough. 2210 * =$viaCache= - forcibly cache a redirect CGI query. It cuts off all the params in a GET url and replace with a "?$cache=..." param. "$viaCache" is meaningful only if "$passthru" is true. 2211 2212Return: none 2213 2214Print output to STDOUT that will cause a 302 redirect to a new URL. 2215Nothing more should be printed to STDOUT after this method has been called. 2216 2217The =$passthru= parameter allows you to pass the parameters that were passed 2218to the current query on to the target URL, as long as it is another URL on the 2219same TWiki installation. If =$passthru= is set to a true value, then TWiki 2220will save the current URL parameters, and then try to restore them on the 2221other side of the redirect. Parameters are stored on the server in a cache 2222file. 2223 2224Note that if =$passthru= is set, then any parameters in =$url= will be lost 2225when the old parameters are restored. if you want to change any parameter 2226values, you will need to do that in the current CGI query before redirecting 2227e.g. 2228<verbatim> 2229my $query = TWiki::Func::getCgiQuery(); 2230$query->param(-name => 'text', -value => 'Different text'); 2231TWiki::Func::redirectCgiQuery( 2232 undef, TWiki::Func::getScriptUrl($web, $topic, 'edit'), 1); 2233</verbatim> 2234=$passthru= does nothing if =$url= does not point to a script in the current 2235TWiki installation. 2236 2237*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 2238 2239=cut 2240 2241sub redirectCgiQuery { 2242 my( $query, $url, $passthru, $viaCache ) = @_; 2243 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2244 return $TWiki::Plugins::SESSION->redirect( $url, $passthru, 0, $viaCache ); 2245} 2246 2247=pod 2248 2249#AddToHEAD 2250---+++ addToHEAD( $id, $header, $requires ) 2251 2252Adds =$header= to the HTML header (the <head> tag). 2253This is useful for Plugins that want to include some javascript and custom css. 2254 * =$id= - Unique ID to prevent the same HTML from being duplicated. Plugins should use a prefix to prevent name clashes (e.g EDITTABLEPLUGIN_JSCALENDAR) 2255 * =$header= - the HTML to be added to the <head> section. The HTML must be valid in a HEAD tag - no checks are performed. 2256 * =requires= optional, comma-separated list of id's of other head blocks this one depends on. Those blocks will be loaded first. 2257 2258All TWiki variables present in =$header= will be expanded before being inserted into the =<head>= section. 2259 2260Note that this is _not_ the same as the HTTP header, which is modified through the Plugins =modifyHeaderHandler=. 2261 2262*Since:* TWiki::Plugins::VERSION 1.1 2263 2264example: 2265<verbatim> 2266TWiki::Func::addToHEAD('PATTERN_STYLE','<link id="twikiLayoutCss" rel="stylesheet" type="text/css" href="%PUBURL%/TWiki/PatternSkin/layout.css" media="all" />'); 2267</verbatim> 2268 2269=cut= 2270 2271sub addToHEAD { 2272 my( $tag, $header, $requires ) = @_; 2273 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2274 $TWiki::Plugins::SESSION->addToHEAD( @_ ); 2275} 2276 2277=pod 2278 2279#ExpandCommonVariables 2280---+++ expandCommonVariables( $text, $topic, $web, $meta ) -> $text 2281 2282Expand all common =%<nop>VARIABLES%= 2283 * =$text= - Text with variables to expand, e.g. ='Current user is %<nop>WIKIUSER%'= 2284 * =$topic= - Current topic name, e.g. ='WebNotify'= 2285 * =$web= - Web name, optional, e.g. ='Main'=. The current web is taken if missing 2286 * =$meta= - topic meta-data to use while expanding (Since TWiki::Plugins::VERSION 1.2) 2287Return: =$text= Expanded text, e.g. ='Current user is <nop>TWikiGuest'= 2288 2289*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 2290 2291See also: expandVariablesOnTopicCreation 2292 2293=cut 2294 2295sub expandCommonVariables { 2296 my( $text, $topic, $web, $meta ) = @_; 2297 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2298 $topic ||= $TWiki::Plugins::SESSION->{topicName}; 2299 $web ||= $TWiki::Plugins::SESSION->{webName}; 2300 return $TWiki::Plugins::SESSION->handleCommonTags( 2301 $text, $web, $topic, $meta ); 2302} 2303 2304=pod 2305 2306#RenderText 2307---+++ renderText( $text, $web ) -> $text 2308 2309Render text from TWiki markup into XHTML as defined in [[%SYSTEMWEB%.TextFormattingRules]] 2310 * =$text= - Text to render, e.g. ='*bold* text and =fixed font='= 2311 * =$web= - Web name, optional, e.g. ='Main'=. The current web is taken if missing 2312Return: =$text= XHTML text, e.g. ='<b>bold</b> and <code>fixed font</code>'= 2313 2314*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 2315 2316=cut 2317 2318sub renderText { 2319# my( $text, $web ) = @_; 2320 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2321 return $TWiki::Plugins::SESSION->renderer->getRenderedVersion( @_ ); 2322} 2323 2324=pod 2325 2326#InternalLink 2327---+++ internalLink( $pre, $web, $topic, $label, $anchor, $createLink ) -> $text 2328 2329Render topic name and link label into an XHTML link. Normally you do not need to call this funtion, it is called internally by =renderText()= 2330 * =$pre= - Text occuring before the TWiki link syntax, optional 2331 * =$web= - Web name, required, e.g. ='Main'= 2332 * =$topic= - Topic name to link to, required, e.g. ='WebNotify'= 2333 * =$label= - Link label, required. Usually the same as =$topic=, e.g. ='notify'= 2334 * =$anchor= - Anchor, optional, e.g. ='#Jump'= 2335 * =$createLink= - Set to ='1'= to add question linked mark after topic name if topic does not exist;<br /> set to ='0'= to suppress link for non-existing topics 2336Return: =$text= XHTML anchor, e.g. ='<a href='/cgi-bin/view/Main/WebNotify#Jump'>notify</a>'= 2337 2338*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 2339 2340=cut 2341 2342sub internalLink { 2343 my $pre = shift; 2344 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2345# my( $web, $topic, $label, $anchor, $anchor, $createLink ) = @_; 2346 return $pre . $TWiki::Plugins::SESSION->renderer->internalLink( @_ ); 2347} 2348 2349=pod 2350 2351#EmailFunctions 2352---++ E-mail 2353 2354#SendEmail 2355---+++ sendEmail ( $text, $retries ) -> $error 2356 2357 * =$text= - text of the mail, including MIME headers 2358 * =$retries= - number of times to retry the send (default 1) 2359Send an e-mail specified as MIME format content. To specify MIME 2360format mails, you create a string that contains a set of header 2361lines that contain field definitions and a message body such as: 2362<verbatim> 2363To: liz@windsor.gov.uk 2364From: serf@hovel.net 2365CC: george@whitehouse.gov 2366Subject: Revolution 2367 2368Dear Liz, 2369 2370Please abolish the monarchy (with King George's permission, of course) 2371 2372Thanks, 2373 2374A. Peasant 2375</verbatim> 2376Leave a blank line between the last header field and the message body. 2377 2378*Since:* TWiki::Plugins::VERSION 1.1 2379 2380=cut 2381 2382sub sendEmail { 2383 #my( $text, $retries ) = @_; 2384 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2385 return $TWiki::Plugins::SESSION->net->sendEmail( @_ ); 2386} 2387 2388=pod 2389 2390#WikiToEmail 2391---+++ wikiToEmail( $wikiName ) -> $email 2392 2393 * =$wikiname= - wiki name of the user 2394Get the e-mail address(es) of the named user. If the user has multiple 2395e-mail addresses (for example, the user is a group), then the list will 2396be comma-separated. 2397 2398*Since:* TWiki::Plugins::VERSION 1.1 2399 2400*Deprecated* in favour of wikinameToEmails, because this function only 2401returns a single email address, where a user may in fact have several. 2402 2403Since TWiki 4.2.1, $wikiName may also be a login name. 2404 2405=cut 2406 2407sub wikiToEmail { 2408 my( $user ) = @_; 2409 my @emails = wikinameToEmails( $user ); 2410 if (scalar(@emails)) { 2411 return $emails[0]; 2412 } 2413 return ''; 2414} 2415 2416=pod 2417 2418#CreatingNewTopicsFunctions 2419---++ Creating New Topics 2420 2421=cut 2422 2423=pod 2424 2425#ExpandVariablesOnTopicCreation 2426---+++ expandVariablesOnTopicCreation ( $text, $web, $topic ) -> $text 2427 2428Expand the limited set of variables that are always expanded during topic creation 2429 * =$text= - the text to process 2430 * =$web= - name of web, optional 2431 * =$topic= - name of topic, optional 2432Return: text with variables expanded 2433 2434*Since:* TWiki::Plugins::VERSION 1.1 2435 2436Expands only the variables expected in templates that must be statically 2437expanded in new content. 2438 2439The expanded variables are: 2440 * =%<nop>DATE%= Signature-format date 2441 * =%<nop>SERVERTIME%= See TWikiVariables 2442 * =%<nop>GMTIME%= See TWikiVariables 2443 * =%<nop>USERNAME%= Base login name 2444 * =%<nop>WIKINAME%= Wiki name 2445 * =%<nop>WIKIUSERNAME%= Wiki name with prepended web 2446 * =%<nop>URLPARAM{...}%= - Parameters to the current CGI query 2447 * =%<nop>NOP%= No-op 2448 2449See also: expandCommonVariables 2450 2451=cut 2452 2453sub expandVariablesOnTopicCreation { 2454 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2455 return $TWiki::Plugins::SESSION->expandVariablesOnTopicCreation( shift, $TWiki::Plugins::SESSION->{user}, @_ ); 2456} 2457 2458=pod 2459 2460#SpecialHandlersFunctions 2461---++ Special Handlers 2462 2463Special handlers can be defined to make functions in plugins behave as if they were built-in to TWiki. 2464 2465=cut 2466 2467=pod= 2468 2469#RegisterTagHandler 2470---+++ registerTagHandler( $var, \&fn, $syntax ) 2471 2472Should only be called from initPlugin. 2473 2474Register a function to handle a simple variable. Handles both %<nop>VAR% and %<nop>VAR{...}%. Registered variables are treated the same as TWiki internal variables, and are expanded at the same time. This is a _lot_ more efficient than using the =commonTagsHandler=. 2475 * =$var= - The name of the variable, i.e. the 'MYVAR' part of %<nop>MYVAR%. The variable name *must* match /^[A-Z][A-Z0-9_]*$/ or it won't work. 2476 * =\&fn= - Reference to the handler function. 2477 * =$syntax= can be 'classic' (the default) or 'context-free'. 'classic' syntax is appropriate where you want the variable to support classic TWiki syntax i.e. to accept the standard =%<nop>MYVAR{ "unnamed" param1="value1" param2="value2" }%= syntax, as well as an unquoted default parameter, such as =%<nop>MYVAR{unquoted parameter}%=. If your variable will only use named parameters, you can use 'context-free' syntax, which supports a more relaxed syntax. For example, %MYVAR{param1=value1, value 2, param3="value 3", param4='value 5"}% 2478 2479*Since:* TWiki::Plugins::VERSION 1.1 2480 2481The variable handler function must be of the form: 2482<verbatim> 2483sub handler(\%session, \%params, $topic, $web) 2484</verbatim> 2485where: 2486 * =\%session= - a reference to the TWiki session object (may be ignored) 2487 * =\%params= - a reference to a TWiki::Attrs object containing parameters. This can be used as a simple hash that maps parameter names to values, with _DEFAULT being the name for the default parameter. 2488 * =$topic= - name of the topic in the query 2489 * =$web= - name of the web in the query 2490 * =$meta= - topic meta-data to use while expanding, can be undef (Since TWiki::Plugins::VERSION 1.4) 2491 * =$textRef= - reference to unexpanded topic text, can be undef (Since TWiki::Plugins::VERSION 1.4) 2492for example, to execute an arbitrary command on the server, you might do this: 2493<verbatim> 2494sub initPlugin{ 2495 TWiki::Func::registerTagHandler('EXEC', \&boo); 2496} 2497 2498sub boo { 2499 my( $session, $params, $topic, $web ) = @_; 2500 my $cmd = $params->{_DEFAULT}; 2501 2502 return "NO COMMAND SPECIFIED" unless $cmd; 2503 2504 my $result = `$cmd 2>&1`; 2505 return $params->{silent} ? '' : $result; 2506} 2507</verbatim> 2508would let you do this: 2509=%<nop>EXEC{"ps -Af" silent="on"}%= 2510 2511Registered tags differ from tags implemented using the old TWiki approach (text substitution in =commonTagsHandler=) in the following ways: 2512 * registered tags are evaluated at the same time as system tags, such as %SERVERTIME. =commonTagsHandler= is only called later, when all system tags have already been expanded (though they are expanded _again_ after =commonTagsHandler= returns). 2513 * registered tag names can only contain alphanumerics and _ (underscore) 2514 * registering a tag =FRED= defines both =%<nop>FRED{...}%= *and also* =%FRED%=. 2515 * registered tag handlers *cannot* return another tag as their only result (e.g. =return '%<nop>SERVERTIME%';=). It won't work. 2516 2517=cut 2518 2519sub registerTagHandler { 2520 my( $tag, $function, $syntax ) = @_; 2521 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2522 # Use an anonymous function so it gets inlined at compile time. 2523 # Make sure we don't mangle the session reference. 2524 TWiki::registerTagHandler( $tag, 2525 sub { 2526 my $record = $TWiki::Plugins::SESSION; 2527 $TWiki::Plugins::SESSION = $_[0]; 2528 my $result = &$function( @_ ); 2529 $TWiki::Plugins::SESSION = $record; 2530 return $result; 2531 }, 2532 $syntax 2533 ); 2534} 2535 2536=pod= 2537 2538#RegisterRESTHandler 2539---+++ registerRESTHandler( $alias, \&fn, ) 2540 2541Should only be called from initPlugin. 2542 2543Adds a function to the dispatch table of the REST interface 2544 * =$alias= - The name . 2545 * =\&fn= - Reference to the function. 2546 2547*Since:* TWiki::Plugins::VERSION 1.1 2548 2549The handler function must be of the form: 2550<verbatim> 2551sub handler(\%session) 2552</verbatim> 2553where: 2554 * =\%session= - a reference to the TWiki session object (may be ignored) 2555 2556From the REST interface, the name of the plugin must be used 2557as the subject of the invokation. 2558 2559Example 2560------- 2561 2562The EmptyPlugin has the following call in the initPlugin handler: 2563<verbatim> 2564 TWiki::Func::registerRESTHandler('example', \&restExample); 2565</verbatim> 2566 2567This adds the =restExample= function to the REST dispatch table 2568for the EmptyPlugin under the 'example' alias, and allows it 2569to be invoked using the URL 2570 2571=http://server:port/bin/rest/EmptyPlugin/example= 2572 2573note that the URL 2574 2575=http://server:port/bin/rest/EmptyPlugin/restExample= 2576 2577(ie, with the name of the function instead of the alias) will not work. 2578 2579=cut 2580 2581sub registerRESTHandler { 2582 my( $alias, $function) = @_; 2583 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2584 my $plugin = caller; 2585 $plugin =~ s/.*:://; # strip off TWiki::Plugins:: prefix 2586 2587 # Use an anonymous function so it gets inlined at compile time. 2588 # Make sure we don't mangle the session reference. 2589 TWiki::registerRESTHandler( $plugin, 2590 $alias, 2591 sub { 2592 my $record = $TWiki::Plugins::SESSION; 2593 $TWiki::Plugins::SESSION = $_[0]; 2594 my $result = &$function( @_ ); 2595 $TWiki::Plugins::SESSION = $record; 2596 return $result; 2597 } 2598 ); 2599} 2600 2601=pod 2602 2603#RegisterExternalHTTPHandler 2604---+++ registerExternalHTTPHandler( \&fn ) 2605 2606Should only be called from initPlugin. 2607 2608Adds a function to modify all the HTTP requests to any external resources. 2609 * =\&fn= - Reference to the function. 2610 2611The handler function must be of the form: 2612<verbatim> 2613sub handler(\%session, $url) -> (\@headers, \%params) 2614</verbatim> 2615where: 2616 * =\%session= - a reference to the TWiki session object (may be ignored) 2617 * =$url= - a URL being requested 2618 2619The returned =\@headers= and =\%params= are added to the request in the same 2620manner as =getExternalResource=, except that =\%params= will not override any 2621entries that have been set earlier. 2622All the params explicitly given by the caller of =getExternalResource= or 2623=postExternalResource= will have the highest precedence. 2624 2625Example: 2626<verbatim> 2627sub initPlugin { 2628 TWiki::Func::registerExternalHTTPHandler( \&handleExternalHTTPRequest ); 2629} 2630 2631sub handleExternalHTTPRequest { 2632 my ($session, $url) = @_; 2633 my @headers; 2634 my %params; 2635 2636 # Add any necessary @headers and %params 2637 push @headers, 'X-Example-Header' => 'Value'; 2638 $params{timeout} = 5; 2639 2640 # Return refs to both 2641 return (\@headers, \%params); 2642} 2643</verbatim> 2644 2645*Since:* TWiki::Plugins::VERSION 6.00 2646 2647=cut 2648 2649sub registerExternalHTTPHandler { 2650 my($function) = @_; 2651 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2652 2653 $TWiki::Plugins::SESSION->net->registerExternalHTTPHandler( 2654 sub { 2655 my $record = $TWiki::Plugins::SESSION; 2656 $TWiki::Plugins::SESSION = $_[0]; 2657 my @result = &$function( @_ ); 2658 $TWiki::Plugins::SESSION = $record; 2659 return @result; 2660 }, 2661 ); 2662} 2663 2664=pod 2665 2666#DecodeFormatTokens 2667---+++ decodeFormatTokens($str) -> $unencodedString 2668 2669TWiki has an informal standard set of tokens used in =format= 2670parameters that are used to block evaluation of paramater strings. 2671For example, if you were to write 2672 2673=%<nop>MYTAG{format="%<nop>WURBLE%"}%= 2674 2675then %<nop>WURBLE would be expanded *before* %<NOP>MYTAG is evaluated. To avoid 2676this TWiki uses escapes in the format string. For example: 2677 2678=%<nop>MYTAG{format="$percntWURBLE$percnt"}%= 2679 2680This lets you enter arbitrary strings into parameters without worrying that 2681TWiki will expand them before your plugin gets a chance to deal with them 2682properly. Once you have processed your tag, you will want to expand these 2683tokens to their proper value. That's what this function does. 2684 2685| *Escape:* | *Expands To:* | 2686| =$n= or =$n()= | New line. Use =$n()= if followed by alphanumeric character, e.g. write =Foo$n()Bar= instead of =Foo$nBar= | 2687| =$nop= or =$nop()= | Is a "no operation". | 2688| =$quot= | Double quote (="=) | 2689| =$aquot= | Apostrophe quote (='=) | 2690| =$percnt= | Percent sign (=%=) | 2691| =$dollar= | Dollar sign (=$=) | 2692| =$lt= | Less than sign (=<=) | 2693| =$gt= | Greater than sign (=>=) | 2694 2695Note that $quot, $aquot, $percnt and $dollar all work *even if they are followed by 2696alphanumeric characters*. You have been warned! 2697 2698*Since:* TWiki::Plugins::VERSION 1.2 2699 2700=cut 2701 2702sub decodeFormatTokens { 2703 return TWiki::expandStandardEscapes( @_ ); 2704} 2705 2706=pod 2707 2708#SearchingFunctions 2709---++ Searching 2710 2711=cut 2712 2713=pod 2714 2715#SearchInWebContent 2716---+++ searchInWebContent($searchString, $web, \@topics, \%options ) -> \%map 2717 2718Search for a string in the content of a web. The search is over all content, including meta-data. Meta-data matches will be returned as formatted lines within the topic content (meta-data matches are returned as lines of the format %META:\w+{.*}%) 2719 * =$searchString= - the search string, in egrep format 2720 * =$web= - The web to search in 2721 * =\@topics= - reference to a list of topics to search 2722 * =\%option= - reference to an options hash 2723The =\%options= hash may contain the following options: 2724 * =type= - if =regex= will perform a egrep-syntax RE search (default '') 2725 * =casesensitive= - false to ignore case (default true) 2726 * =files_without_match= - true to return files only (default false). If =files_without_match= is specified, it will return on the first match in each topic (i.e. it will return only one match per topic, and will not return matching lines). 2727 2728The return value is a reference to a hash which maps each matching topic 2729name to a list of the lines in that topic that matched the search, 2730as would be returned by 'grep'. 2731 2732To iterate over the returned topics use: 2733<verbatim> 2734my $result = TWiki::Func::searchInWebContent( "Slimy Toad", $web, \@topics, 2735 { casesensitive => 0, files_without_match => 0 } ); 2736foreach my $topic (keys %$result ) { 2737 foreach my $matching_line ( @{$result->{$topic}} ) { 2738 ...etc 2739</verbatim> 2740 2741*Since:* TWiki::Plugins::VERSION 1.1 2742 2743=cut 2744 2745sub searchInWebContent { 2746 #my( $searchString, $web, $topics, $options ) = @_; 2747 2748 return $TWiki::Plugins::SESSION->{store}->searchInWebContent( @_ ); 2749} 2750 2751=pod 2752 2753#PluginSpecificFileHandlingFunctions 2754---++ Plugin-specific File Handling 2755 2756=cut 2757 2758=pod 2759 2760#GetWorkArea 2761---+++ getWorkArea( $pluginName ) -> $directorypath 2762 2763Gets a private directory for Plugin use. The Plugin is entirely responsible 2764for managing this directory; TWiki will not read from it, or write to it. 2765 2766The directory is guaranteed to exist, and to be writable by the webserver 2767user. By default it will *not* be web accessible. 2768 2769The directory and it's contents are permanent, so Plugins must be careful 2770to keep their areas tidy. 2771 2772*Since:* TWiki::Plugins::VERSION 1.1 (Dec 2005) 2773 2774=cut 2775 2776sub getWorkArea { 2777 my( $plugin ) = @_; 2778 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2779 return $TWiki::Plugins::SESSION->{store}->getWorkArea( $plugin ); 2780} 2781 2782=pod 2783 2784#ReadFile 2785---+++ readFile( $filename ) -> $text 2786 2787Read file, low level. Used for Plugin workarea. 2788 * =$filename= - Full path name of file 2789Return: =$text= Content of file, empty if not found 2790 2791__NOTE:__ Use this function only for the Plugin workarea, *not* for topics and attachments. Use the appropriate functions to manipulate topics and attachments. 2792 2793*Since:* TWiki::Plugins::VERSION 1.000 (07 Dec 2002) 2794 2795=cut 2796 2797sub readFile { 2798 my $name = shift; 2799 my $data = ''; 2800 open( IN_FILE, "<$name" ) || return ''; 2801 local $/ = undef; # set to read to EOF 2802 $data = <IN_FILE>; 2803 close( IN_FILE ); 2804 $data = '' unless $data; # no undefined 2805 return $data; 2806} 2807 2808=pod 2809 2810#SaveFile 2811---+++ saveFile( $filename, $text ) 2812 2813Save file, low level. Used for Plugin workarea. 2814 * =$filename= - Full path name of file 2815 * =$text= - Text to save 2816Return: none 2817 2818__NOTE:__ Use this function only for the Plugin workarea, *not* for topics and attachments. Use the appropriate functions to manipulate topics and attachments. 2819 2820*Since:* TWiki::Plugins::VERSION 1.000 (07 Dec 2002) 2821 2822=cut 2823 2824sub saveFile { 2825 my( $name, $text ) = @_; 2826 2827 unless ( open( FILE, ">$name" ) ) { 2828 die "Can't create file $name - $!\n"; 2829 } 2830 print FILE $text; 2831 close( FILE); 2832} 2833 2834=pod 2835 2836#ReadOnlyAndMirrorWebs 2837---++ Read-only and Mirror Webs 2838 2839The following functions are for ReadOnlyAndMirrorWebs. 2840 2841=cut 2842 2843=pod 2844 2845#GetSiteName 2846---+++ getSiteName() -> $siteName 2847 2848Returns the current site name if it's defined. Otherwise returns the null 2849string. 2850=cut 2851 2852sub getSiteName { 2853 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2854 2855 return $TWiki::cfg{ReadOnlyAndMirrorWebs}{SiteName} || ''; 2856} 2857 2858 2859 2860=pod 2861 2862#GetContentMode 2863---+++ getContentMode( $web ) -> $contentMode 2864 2865Returns the content mode of the specified $web. 2866Please read ReadOnlyAndMirrorWebs about content mode. 2867 2868*Since:* TWiki::Plugins::VERSION 6.00 2869=cut 2870 2871sub getContentMode { 2872# my $web = shift; 2873 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2874 2875 $TWiki::Plugins::SESSION->getContentMode($_[0]); 2876} 2877 2878=pod 2879 2880#WebWritable 2881---+++ webWritable( $web ) -> $boolean 2882 2883Checks if the web is wriable on this site - if it's master or local. 2884Returns true if it's writable. Returns false otherwise. 2885 2886*Since:* TWiki::Plugins::VERSION 6.00 2887=cut 2888 2889sub webWritable { 2890# my $web = shift; 2891 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2892 2893 return $TWiki::Plugins::SESSION->webWritable($_[0]); 2894} 2895 2896=pod 2897 2898#UsingMultipleDisks 2899---++ Using multiple disks 2900 2901The following functions are for UsingMultipleDisks. 2902 2903=cut 2904 2905=pod 2906 2907#GetDiskList 2908---+++ getDiskList() -> @diskIDs 2909 2910Returns IDs of disks used by TWiki. An disk ID is "" (a null string) or a decimal number without leading 0. 2911 2912*Since:* TWiki::Plugins::VERSION 6.00 2913=cut 2914 2915sub getDiskList { 2916 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2917 2918 return $TWiki::Plugins::SESSION->getDiskList(); 2919} 2920 2921=pod 2922 2923#GetDiskInfo 2924---+++ getDiskInfo($web, [$diskID]) -> ($dataDir, $pubDir, $diskID) 2925 2926Returns the relevant paths and the disk ID of the specified web on the specified site. 2927 2928*Since:* TWiki::Plugins::VERSION 6.00 2929=cut 2930 2931sub getDiskInfo { 2932 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2933 2934 return $TWiki::Plugins::SESSION->getDiskInfo(@_); 2935} 2936 2937=pod 2938 2939#TrashWebName 2940---+++ trashWebName(web => $web | disk => $diskID) -> $trashWebName 2941 2942Returns the name of the trash web to which topics of the =$web= web are moved. 2943Or returns the name of the trash web of the specified disk. 2944 2945Each disk (file system) TWiki uses needs to have a trash web since a topic deletion may entail an attachment directory move, which is possible only within the same disk/file system. 2946 2947*Since:* TWiki::Plugins::VERSION 6.00 2948=cut 2949 2950sub trashWebName { 2951 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 2952 2953 return $TWiki::Plugins::SESSION->trashWebName(@_); 2954} 2955 2956=pod 2957 2958#GeneralUtilitiesFunctions 2959---++ General Utilities 2960 2961=cut 2962 2963=pod 2964 2965#GetRegularExpression 2966---+++ getRegularExpression( $name ) -> $expr 2967 2968Retrieves a TWiki predefined regular expression or character class. 2969 * =$name= - Name of the expression to retrieve. See notes below 2970Return: String or precompiled regular expression matching as described below. 2971 2972*Since:* TWiki::Plugins::VERSION 1.020 (9 Feb 2004) 2973 2974__Note:__ TWiki internally precompiles several regular expressions to 2975represent various string entities in an <nop>I18N-compatible manner. Plugins 2976authors are encouraged to use these in matching where appropriate. The 2977following are guaranteed to be present. Others may exist, but their use 2978is unsupported and they may be removed in future TWiki versions. 2979 2980In the table below, the expression marked type 'String' are intended for 2981use within character classes (i.e. for use within square brackets inside 2982a regular expression), for example: 2983<verbatim> 2984 my $upper = TWiki::Func::getRegularExpression('upperAlpha'); 2985 my $alpha = TWiki::Func::getRegularExpression('mixedAlpha'); 2986 my $capitalized = qr/[$upper][$alpha]+/; 2987</verbatim> 2988Those expressions marked type 'RE' are precompiled regular expressions that can be used outside square brackets. For example: 2989<verbatim> 2990 my $webRE = TWiki::Func::getRegularExpression('webNameRegex'); 2991 my $isWebName = ( $s =~ m/$webRE/ ); 2992</verbatim> 2993 2994| *Name* | *Matches* | *Type* | 2995| upperAlpha | Upper case characters | String | 2996| upperAlphaNum | Upper case characters and digits | String | 2997| lowerAlpha | Lower case characters | String | 2998| lowerAlphaNum | Lower case characters and digits | String | 2999| numeric | Digits | String | 3000| mixedAlpha | Alphabetic characters | String | 3001| mixedAlphaNum | Alphanumeric characters | String | 3002| wikiWordRegex | WikiWords | RE | 3003| webNameRegex | User web names | RE | 3004| anchorRegex | #AnchorNames | RE | 3005| abbrevRegex | Abbreviations e.g. GOV, IRS | RE | 3006| emailAddrRegex | email@address.com | RE | 3007| tagNameRegex | Standard variable names e.g. %<nop>THIS_BIT% (THIS_BIT only) | RE | 3008 3009=cut 3010 3011sub getRegularExpression { 3012 my ( $regexName ) = @_; 3013 return $TWiki::regex{$regexName}; 3014} 3015 3016=pod 3017 3018#NormalizeWebTopicName 3019---+++ normalizeWebTopicName($web, $topic) -> ($web, $topic) 3020 3021Parse a web and topic name, supplying defaults as appropriate. 3022 * =$web= - Web name, identifying variable, or empty string 3023 * =$topic= - Topic name, may be a web.topic string, required. 3024Return: the parsed Web/Topic pair 3025 3026*Since:* TWiki::Plugins::VERSION 1.1 3027 3028| *Input* | *Return* | 3029| <tt>( 'Web', 'Topic' ) </tt> | <tt>( 'Web', 'Topic' ) </tt> | 3030| <tt>( '', 'Topic' ) </tt> | <tt>( 'Main', 'Topic' ) </tt> | 3031| <tt>( '', '' ) </tt> | <tt>( 'Main', 'WebHome' ) </tt> | 3032| <tt>( '', 'Web/Topic' ) </tt> | <tt>( 'Web', 'Topic' ) </tt> | 3033| <tt>( '', 'Web/Subweb/Topic' ) </tt> | <tt>( 'Web/Subweb', 'Topic' ) </tt> | 3034| <tt>( '', 'Web.Topic' ) </tt> | <tt>( 'Web', 'Topic' ) </tt> | 3035| <tt>( '', 'Web.Subweb.Topic' ) </tt> | <tt>( 'Web/Subweb', 'Topic' ) </tt> | 3036| <tt>( 'Web1', 'Web2.Topic' )</tt> | <tt>( 'Web2', 'Topic' ) </tt> | 3037 3038Note that hierarchical web names (!Web.SubWeb) are only available if hierarchical webs are enabled in =configure=. 3039 3040The symbols %<nop>USERSWEB%, %<nop>SYSTEMWEB% and %<nop>DOCWEB% can be used in the input to represent the web names set in $cfg{UsersWebName} and $cfg{SystemWebName}. For example: 3041| *Input* | *Return* | 3042| <tt>( '%<nop>USERSWEB%', 'Topic' )</tt> | <tt>( 'Main', 'Topic' ) </tt> | 3043| <tt>( '%<nop>SYSTEMWEB%', 'Topic' )</tt> | <tt>( 'TWiki', 'Topic' ) </tt> | 3044| <tt>( '', '%<nop>DOCWEB%.Topic' )</tt> | <tt>( 'TWiki', 'Topic' ) </tt> | 3045 3046=cut 3047 3048sub normalizeWebTopicName { 3049 #my( $web, $topic ) = @_; 3050 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3051 return $TWiki::Plugins::SESSION->normalizeWebTopicName( @_ ); 3052} 3053 3054=pod 3055 3056#SanitizeAttachmentName 3057---+++ sanitizeAttachmentName($fname) -> ($fileName, $origName) 3058 3059Given a file namer, sanitise it according to the rules for transforming 3060attachment names. Returns 3061the sanitised name together with the basename before sanitisation. 3062 3063Sanitation includes filtering illegal characters and mapping client 3064file names to legal server names. 3065 3066*Since:* TWiki::Plugins::VERSION 1.2 3067 3068=cut 3069 3070sub sanitizeAttachmentName { 3071 require TWiki::Sandbox; 3072 return TWiki::Sandbox::sanitizeAttachmentName(@_); 3073} 3074 3075=pod 3076 3077#BuildWikiWord 3078---+++ buildWikiWord( $text ) -> $text 3079 3080Converts arbitrary text to a WikiWord. 3081 * =$pre= - Arbitrary Text 3082Return: =$text= 3083 3084*Since:* TWiki::Plugins::VERSION 1.3 (18 Jan 2010) 3085 3086=cut 3087 3088sub buildWikiWord { 3089 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3090 return $TWiki::Plugins::SESSION->{renderer}->buildWikiWord( @_ ); 3091} 3092 3093=pod 3094 3095#SpaceOutWikiWord 3096---+++ spaceOutWikiWord( $word, $sep ) -> $text 3097 3098Spaces out a wiki word by inserting a string between each word component. 3099Word component boundaries are transitions from lowercase to uppercase or numeric, 3100from numeric to uppercase or lowercase, and from uppercase to numeric characters. 3101 3102Parameter $sep defines the separator between the word components, the default is a space. 3103 3104Example: "ABC2015ProjectCharter" results in "ABC 2015 Project Charter" 3105 3106*Since:* TWiki::Plugins::VERSION 1.2 3107 3108=cut 3109 3110sub spaceOutWikiWord { 3111 #my ( $word, $sep ) = @_; 3112 return TWiki::spaceOutWikiWord(@_); 3113} 3114 3115=pod 3116 3117#WriteWarning 3118---+++ writeWarning( $text ) 3119 3120Log Warning that may require admin intervention to data/warning.txt 3121 * =$text= - Text to write; timestamp gets added 3122Return: none 3123 3124*Since:* TWiki::Plugins::VERSION 1.020 (16 Feb 2004) 3125 3126=cut 3127 3128sub writeWarning { 3129# my( $text ) = @_; 3130 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3131 my ($message)=@_; 3132 return $TWiki::Plugins::SESSION->writeWarning( "(".caller().") ".$message ); 3133} 3134 3135=pod 3136 3137#WriteDebug 3138---+++ writeDebug( $text ) 3139 3140Log debug message to data/debug.txt 3141 * =$text= - Text to write; timestamp gets added 3142Return: none 3143 3144*Since:* TWiki::Plugins::VERSION 1.020 (16 Feb 2004) 3145 3146=cut 3147 3148sub writeDebug { 3149# my( $text ) = @_; 3150 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3151 return $TWiki::Plugins::SESSION->writeDebug( @_ ); 3152} 3153 3154=pod 3155 3156---+++ writeLog( $action, $extra, $web, $topic, $user ) 3157 3158Write the log for an event to the logfile. 3159 * =$action= - name of the event, such as ='blacklist'=. 3160 * =$extra= - arbitrary extra information to add to the event. 3161 * =$web= - web name, optional. Base web is taken if empty. Ignored if web is specified in =$topic=. 3162 * =$topic= - topic name, optional. Can be =Topic= or =Web.Topic=. Base topic is taken if empty. 3163 * =$user= - !WikiName, login name or cUID of user, optional. Name of logged-in user is taken if not specified. 3164Return: none 3165 3166*Since:* TWiki::Plugins::VERSION 1.4 3167 3168__Example:__ Calling =TWiki::Func::writeLog( 'blacklist', 'Magic number is missing' )= 3169will add a log entry like this: 3170<verbatim> 3171| 2011-01-19 - 01:13 | guest | blacklist | TWiki.TWikiRegistration | Magic number is missing | 1.2.3.4 | 3172</verbatim> 3173 3174__Note:__ Older plugins that use =$TWiki::cfg{LogFileName}= or call the internal TWiki 3175function directly should be fixed to use =writeLog=. 3176 3177To maintain compatibility with older TWiki releases, you can write conditional code as follows: 3178<verbatim> 3179 if( defined &TWiki::Func::writeLog ) { 3180 # use writeLog 3181 TWiki::Func::writeLog( 'myevent', $extra, $web, $topic ); 3182 } else { 3183 # deprecated code if plugin is used in older TWiki releases 3184 $TWiki::Plugins::VERSION > 1.1 3185 ? $TWiki::Plugins::SESSION->writeLog( 'myevent', "$web.$topic", $extra ) 3186 : TWiki::Store::writeLog( 'myevent', "$web.$topic", $extra ); 3187 } 3188</verbatim> 3189 3190=cut 3191 3192sub writeLog { 3193 my( $action, $extra, $web, $topic, $user ) = @_; 3194 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3195 3196 $web ||= $TWiki::Plugins::SESSION->{SESSION_TAGS}{BASEWEB}; 3197 $topic ||= $TWiki::Plugins::SESSION->{SESSION_TAGS}{BASETOPIC}; 3198 ( $web, $topic ) = normalizeWebTopicName( $web, $topic ); 3199 3200 return $TWiki::Plugins::SESSION->writeLog( $action, "$web.$topic", $extra, $user ); 3201} 3202 3203=pod 3204 3205#FormatTime 3206---+++ formatTime( $time, $format, $timezone ) -> $text 3207 3208Format the time in seconds into the desired time string 3209 * =$time= - Time in epoc seconds 3210 * =$format= - Format type, optional. Default e.g. ='2014-12-31 - 19:30'=. Can be ='$iso'= (e.g. ='2014-12-31T19:30Z'=), ='$rcs'= (e.g. ='2014/12/31 23:59:59'=, ='$http'= for HTTP header format (e.g. ='The, 2014-07-23 07:21:56 GMT'=), or any string with tokens ='$seconds, $minutes, $hours, $day, $wday, $month, $mo, $year, $ye, $tz'= for seconds, minutes, hours, day of month, day of week, 3 letter month, 2 digit month, 4 digit year, 2 digit year, timezone string, respectively 3211 * =$timezone= - either not defined (uses the displaytime setting), 'gmtime', or 'servertime' 3212Return: =$text= Formatted time string 3213 3214__Note:__ If you used the removed formatGmTime, add a third parameter 'gmtime' 3215 3216*Since:* TWiki::Plugins::VERSION 1.020 (26 Feb 2004) 3217 3218=cut 3219 3220sub formatTime { 3221# my ( $epSecs, $format, $timezone ) = @_; 3222 require TWiki::Time; 3223 return TWiki::Time::formatTime( @_ ); 3224} 3225 3226=pod 3227 3228#IsTrue 3229---+++ isTrue( $value, $default ) -> $boolean 3230 3231Returns 1 if =$value= is true, and 0 otherwise. "true" means set to 3232something with a Perl true value, with the special cases that "off", 3233"false" and "no" (case insensitive) are forced to false. Leading and 3234trailing spaces in =$value= are ignored. 3235 3236If the value is undef, then =$default= is returned. If =$default= is 3237not specified it is taken as 0. 3238 3239*Since:* TWiki::Plugins::VERSION 1.2 3240 3241=cut 3242 3243sub isTrue { 3244# my ( $value, $default ) = @_; 3245 3246 return TWiki::isTrue( @_ ); 3247} 3248 3249=pod 3250 3251#IsValidWikiWord 3252---+++ isValidWikiWord ( $text ) -> $boolean 3253 3254Check for a valid WikiWord or WikiName 3255 * =$text= - Word to test 3256 3257*Since:* TWiki::Plugins::VERSION 1.100 (Dec 2005) 3258 3259=cut 3260 3261sub isValidWikiWord { 3262 return TWiki::isValidWikiWord(@_); 3263} 3264 3265=pod 3266 3267#ExtractParameters 3268---+++ extractParameters($attr ) -> %params 3269 3270Extract all parameters from a variable string and returns a hash of parameters 3271 * =$attr= - Attribute string 3272Return: =%params= Hash containing all parameters. The nameless parameter is stored in key =_DEFAULT= 3273 3274*Since:* TWiki::Plugins::VERSION 1.025 (26 Aug 2004) 3275 3276 * Example: 3277 * Variable: =%<nop>TEST{ 'nameless' name1="val1" name2="val2" }%= 3278 * First extract text between ={...}= to get: ='nameless' name1="val1" name2="val2"= 3279 * Then call this on the text: <br /> 3280 * params = TWiki::Func::extractParameters( $text );= 3281 * The =%params= hash contains now: <br /> 3282 =_DEFAULT => 'nameless'= <br /> 3283 =name1 => "val1"= <br /> 3284 =name2 => "val2"= 3285 3286=cut 3287 3288sub extractParameters { 3289 my( $attr ) = @_; 3290 require TWiki::Attrs; 3291 my $params = new TWiki::Attrs( $attr ); 3292 # take out _RAW and _ERROR (compatibility) 3293 delete $params->{_RAW}; 3294 delete $params->{_ERROR}; 3295 return %$params; 3296} 3297 3298=pod 3299 3300#ExtractNameValuePair 3301---+++ extractNameValuePair( $attr, $name ) -> $value 3302 3303Extract a named or unnamed value from a variable parameter string. 3304 * =$attr= - Attribute string 3305 * =$name= - Name, optional 3306Return: =$value= Extracted value 3307 3308*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 3309 3310 * Example: 3311 * Variable: =%<nop>TEST{ 'nameless' name1="val1" name2="val2" }%= 3312 * First extract text between ={...}= to get: ='nameless' name1="val1" name2="val2"= 3313 * Then call this on the text: <br /> 3314 =my $noname = TWiki::Func::extractNameValuePair( $text );= <br /> 3315 =my $val1 = TWiki::Func::extractNameValuePair( $text, "name1" );= <br /> 3316 =my $val2 = TWiki::Func::extractNameValuePair( $text, "name2" );= 3317 3318__Note:__ Function TWiki::Func::extractParameters is more efficient for extracting several parameters 3319 3320=cut 3321 3322sub extractNameValuePair { 3323 require TWiki::Attrs; 3324 return TWiki::Attrs::extractValue( @_ ); 3325} 3326 3327=pod 3328 3329#EntityEncode 3330---+++ entityEncode( $text, $extra ) -> $text 3331 3332Entity encode text. 3333 * =$text= - Text to encode, may be empty 3334 * =$extra= - Additional characters to include in the set of encoded 3335 characters, optional 3336Return: =$text= Entity encoded text 3337 3338*Since:* TWiki::Plugins::VERSION 6.00 3339 3340Escape special characters to HTML numeric entities. This is *not* a generic 3341encoding, it is tuned specifically for use in TWiki. 3342 3343HTML4.0 spec: 3344"Certain characters in HTML are reserved for use as markup and must be 3345escaped to appear literally. The "<" character may be represented with 3346an <em>entity</em>, <strong class=html>&lt;</strong>. Similarly, ">" 3347is escaped as <strong class=html>&gt;</strong>, and "&" is escaped 3348as <strong class=html>&amp;</strong>. If an attribute value contains a 3349double quotation mark and is delimited by double quotation marks, then the 3350quote should be escaped as <strong class=html>&quot;</strong>. 3351 3352Other entities exist for special characters that cannot easily be entered 3353with some keyboards..." 3354 3355This method encodes HTML special and any non-printable ASCII 3356characters (except for \n and \r) using numeric entities. 3357 3358FURTHER this method also encodes characters that are special in TWiki 3359meta-language. 3360 3361$extras is an optional param that may be used to include *additional* 3362characters in the set of encoded characters. It should be a string 3363containing the additional chars. 3364 3365=cut 3366 3367sub entityEncode { 3368# my ( $text, $type ) = @_; 3369 return TWiki::entityEncode( @_ ); 3370} 3371 3372=pod 3373 3374#EntityDecode 3375---+++ entityDecode( $text ) -> $text 3376 3377Decode all numeric entities (e.g. &#123;). _Does not_ decode 3378named entities such as &amp; (use HTML::Entities for that) 3379 * =$text= - Text to decode, may be empty 3380Return: =$text= Entity decoded text 3381 3382*Since:* TWiki::Plugins::VERSION 6.00 3383 3384=cut 3385 3386sub entityDecode { 3387 return TWiki::entityDecode( @_ ); 3388} 3389 3390=pod 3391 3392#UrlEncode 3393---+++ urlEncode( $text ) -> $text 3394 3395URL encode text, mainly used to encode URL parameters. 3396 * =$text= - Text to encode, may be empty 3397Return: =$text= URL encoded text 3398 3399*Since:* TWiki::Plugins::VERSION 6.00 3400 3401Encoding is done by converting characters that are illegal in 3402URLs to their %NN equivalents. This method is used for encoding 3403strings that must be embedded _verbatim_ in URLs; it cannot 3404be applied to URLs themselves, as it escapes reserved 3405characters such as = and ?. 3406 3407RFC 1738, Dec. '94: 3408<verbatim> 3409 ...Only alphanumerics [0-9a-zA-Z], the special 3410 characters $-_.+!*'(), and reserved characters used for their 3411 reserved purposes may be used unencoded within a URL. 3412</verbatim> 3413 3414Reserved characters are $&+,/:;=?@ - these are _also_ encoded by 3415this method. 3416 3417This URL-encoding handles all character encodings including ISO-8859-*, 3418KOI8-R, EUC-* and UTF-8. 3419 3420This may not handle EBCDIC properly, as it generates an EBCDIC URL-encoded 3421URL, but mainframe web servers seem to translate this outbound before it hits browser 3422- see CGI::Util::escape for another approach. 3423 3424=cut 3425 3426sub urlEncode { 3427 return TWiki::urlEncode( @_ ); 3428} 3429 3430=pod 3431 3432#UrlDecode 3433---+++ urlDecode( $text ) -> $text 3434 3435URL decode text, mainly used to decode URL parameters. 3436 * =$text= - Text to decode, may be empty 3437Return: =$text= URL decoded text 3438 3439*Since:* TWiki::Plugins::VERSION 6.00 3440 3441=cut 3442 3443sub urlDecode { 3444 return TWiki::urlDecode( @_ ); 3445} 3446 3447=pod 3448 3449#GetDebugFilePath 3450---+++ getDebugFilePath() -> $path 3451 3452You may want to have an external program write to the debug file. 3453This function returns the path to it. An external program may corrupt 3454the debug file, but that's no big deal -- it's a debug file. 3455 3456The return value is =$TWiki::cfg{DebugFileName}= with =%<nop>DATE%= 3457and other "variables" resolved. =$TWiki::cfg{DebugFileName}= is an 3458absolute path in most cases. If it's not, then the current directory 3459is prepended in the return value. 3460 3461*Since:* TWiki::Plugins::VERSION 6.10 3462 3463=cut 3464 3465use Cwd; 3466 3467sub getDebugFilePath { 3468 my $path = TWiki::_fileNameToPath( $TWiki::cfg{DebugFileName} ); 3469 unless ( $path =~ m:^/: ) { 3470 $path = abs_path($path); 3471 } 3472 return $path; 3473} 3474 3475=pod 3476 3477#DeprecatedFunctions 3478---++ Deprecated functions 3479 3480From time-to-time, the TWiki developers will add new functions to the interface (either to TWikiFuncDotPm, or new handlers). Sometimes these improvements mean that old functions have to be deprecated to keep the code manageable. When this happens, the deprecated functions will be supported in the interface for at least one more TWiki release, and probably longer, though this cannot be guaranteed. 3481 3482Updated plugins may still need to define deprecated handlers for compatibility with old TWiki versions. In this case, the plugin package that defines old handlers can suppress the warnings in %<nop>FAILEDPLUGINS%. 3483 3484This is done by defining a map from the handler name to the =TWiki::Plugins= version _in which the handler was first deprecated_. For example, if we need to define the =endRenderingHandler= for compatibility with =TWiki::Plugins= versions before 1.1, we would add this to the plugin: 3485<verbatim> 3486package TWiki::Plugins::SinkPlugin; 3487use vars qw( %TWikiCompatibility ); 3488$TWikiCompatibility{endRenderingHandler} = 1.1; 3489</verbatim> 3490If the currently-running TWiki version is 1.1 _or later_, then the _handler will not be called_ and _the warning will not be issued_. TWiki with versions of =TWiki::Plugins= before 1.1 will still call the handler as required. 3491 3492The following functions are retained for compatibility only. You should 3493stop using them as soon as possible. 3494 3495#GetScriptUrlPath 3496---+++ getScriptUrlPath( ) -> $path 3497 3498Get script URL path 3499 3500*DEPRECATED* since 1.1 - use =getScriptUrl= instead. 3501 3502Return: =$path= URL path of TWiki scripts, e.g. ="/cgi-bin"= 3503 3504*WARNING:* you are strongly recommended *not* to use this function, as the 3505{ScriptUrlPaths} URL rewriting rules will not apply to urls generated 3506using it. 3507 3508*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 3509 3510=cut 3511 3512sub getScriptUrlPath { 3513 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3514 return $TWiki::Plugins::SESSION->getScriptUrl( 0, '' ); 3515} 3516 3517=pod 3518 3519#GetOopsUrl 3520---+++ getOopsUrl( $web, $topic, $template, $param1, $param2, $param3, $param4 ) -> $url 3521 3522Compose fully qualified 'oops' dialog URL 3523 * =$web= - Web name, e.g. ='Main'=. The current web is taken if empty 3524 * =$topic= - Topic name, e.g. ='WebNotify'= 3525 * =$template= - Oops template name, e.g. ='oopsmistake'=. The 'oops' is optional; 'mistake' will translate to 'oopsmistake'. 3526 * =$param1= ... =$param4= - Parameter values for %<nop>PARAM1% ... %<nop>PARAMn% variables in template, optional 3527Return: =$url= URL, e.g. ="http://example.com:80/cgi-bin/oops.pl/ Main/WebNotify?template=oopslocked&param1=joe"= 3528 3529*DEPRECATED* since 1.1, the recommended approach is to throw an [[TWikiOopsExceptionDotPm][oops exception]]. 3530<verbatim> 3531 use Error qw( :try ); 3532 3533 throw TWiki::OopsException( 3534 'toestuckerror', 3535 web => $web, 3536 topic => $topic, 3537 params => [ 'I got my toe stuck' ]); 3538</verbatim> 3539(this example will use the =oopstoestuckerror= template.) 3540 3541If this is not possible (e.g. in a REST handler that does not trap the exception) 3542then you can use =getScriptUrl= instead: 3543<verbatim> 3544 my $url = TWiki::Func::getScriptUrl($web, $topic, 'oops', 3545 template => 'oopstoestuckerror', 3546 param1 => 'I got my toe stuck'); 3547 TWiki::Func::redirectCgiQuery( undef, $url ); 3548 return 0; 3549</verbatim> 3550 3551*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 3552 3553=cut 3554 3555sub getOopsUrl { 3556 my( $web, $topic, $template, @params ) = @_; 3557 3558 my $n = 1; 3559 @params = map { 'param'.($n++) => $_ } @params; 3560 return getScriptUrl( $web, $topic, 'oops', 3561 template => $template, 3562 @params ); 3563} 3564 3565=pod 3566 3567#PermissionsSet 3568---+++ permissionsSet( $web ) -> $boolean 3569 3570Test if any access restrictions are set for this web, ignoring settings on 3571individual pages 3572 * =$web= - Web name, required, e.g. ='Sandbox'= 3573 3574*Since:* TWiki::Plugins::VERSION 1.000 (27 Feb 2001) 3575 3576*DEPRECATED* since 1.2 - use =getPreferencesValue= instead to determine 3577what permissions are set on the web, for example: 3578<verbatim> 3579foreach my $type ( 'ALLOW', 'DENY' ) { 3580 foreach my $action ( 'CHANGE', 'VIEW' ) { 3581 my $pref = $type . 'WEB' . $action; 3582 my $val = getPreferencesValue( $pref, $web ) || ''; 3583 if( $val =~ /\S/ ) { 3584 print "$pref is set to $val on $web\n"; 3585 } 3586 } 3587} 3588</verbatim> 3589 3590=cut 3591 3592sub permissionsSet { 3593 my( $web ) = @_; 3594 3595 foreach my $type ( 'ALLOW', 'DENY' ) { 3596 foreach my $action ( 'CHANGE', 'VIEW', 'RENAME' ) { 3597 my $pref = $type . 'WEB' . $action; 3598 my $val = getPreferencesValue( $pref, $web ) || ''; 3599 return 1 if( $val =~ /\S/ ); 3600 } 3601 } 3602 3603 return 0; 3604} 3605 3606=pod 3607 3608#GetPublicWebList 3609---+++ getPublicWebList( ) -> @webs 3610 3611*DEPRECATED* since 1.1 - use =getListOfWebs= instead. 3612 3613Get list of all public webs, e.g. all webs that do not have the =NOSEARCHALL= flag set in the WebPreferences 3614 3615Return: =@webs= List of all public webs, e.g. =( 'Main', 'Know', 'TWiki' )= 3616 3617*Since:* TWiki::Plugins::VERSION 1.000 (07 Dec 2002) 3618 3619=cut 3620 3621sub getPublicWebList { 3622 ASSERT($TWiki::Plugins::SESSION) if DEBUG; 3623 return $TWiki::Plugins::SESSION->{store}->getListOfWebs("user,public"); 3624} 3625 3626=pod 3627 3628#FormatGmTime 3629---+++ formatGmTime( $time, $format ) -> $text 3630 3631*DEPRECATED* since 1.1 - use =formatTime= instead. 3632 3633Format the time to GM time 3634 * =$time= - Time in epoc seconds 3635 * =$format= - Format type, optional. Default e.g. ='31 Dec 2002 - 19:30'=, can be ='iso'= (e.g. ='2002-12-31T19:30Z'=), ='rcs'= (e.g. ='2001/12/31 23:59:59'=, ='http'= for HTTP header format (e.g. ='Thu, 23 Jul 1998 07:21:56 GMT'=) 3636Return: =$text= Formatted time string 3637 3638*Since:* TWiki::Plugins::VERSION 1.000 (7 Dec 2002) 3639 3640=cut 3641 3642sub formatGmTime { 3643# my ( $epSecs, $format ) = @_; 3644 3645 # FIXME: Write warning based on flag (disabled for now); indicate who is calling this function 3646 ## writeWarning( 'deprecated use of Func::formatGmTime' ); 3647 3648 require TWiki::Time; 3649 return TWiki::Time::formatTime( @_, 'gmtime' ); 3650} 3651 3652=pod 3653 3654#GetDataDir 3655---+++ getDataDir( ) -> $dir 3656 3657*DEPRECATED* since 1.1 - use the "Webs, Topics and Attachments" functions to manipulate topics instead 3658 3659Get data directory (topic file root) 3660 3661Return: =$dir= Data directory, e.g. ='/twiki/data'= 3662 3663This function violates store encapsulation and is therefore *deprecated*. 3664 3665*Since:* TWiki::Plugins::VERSION 1.000 (07 Dec 2002) 3666 3667=cut 3668 3669sub getDataDir { 3670 return $TWiki::Plugins::SESSION->getDataDir($_[0]); 3671} 3672 3673=pod 3674 3675#GetPubDir 3676---+++ getPubDir( ) -> $dir 3677 3678*DEPRECATED* since 1.1 - use the "Webs, Topics and Attachments" functions to manipulateattachments instead 3679 3680Get pub directory (file attachment root). Attachments are in =$dir/Web/TopicName= 3681 3682Return: =$dir= Pub directory, e.g. ='/htdocs/twiki/pub'= 3683 3684This function violates store encapsulation and is therefore *deprecated*. 3685 3686Use =readAttachment= and =saveAttachment= instead. 3687 3688*Since:* TWiki::Plugins::VERSION 1.000 (07 Dec 2002) 3689 3690=cut 3691 3692sub getPubDir { 3693 return $TWiki::Plugins::SESSION->getPubDir($_[0]); 3694} 3695 3696=pod 3697 3698#CheckDependencies 3699---+++ checkDependencies( $moduleName, $dependenciesRef ) -> $error 3700 3701*DEPRECATED* since 1.1 - use TWiki:Plugins.BuildContrib and define DEPENDENCIES that can be statically 3702evaluated at install time instead. It is a lot more efficient. 3703 3704*Since:* TWiki::Plugins::VERSION 1.025 (01 Aug 2004) 3705 3706=cut 3707 3708sub checkDependencies { 3709 my ( $context, $deps ) = @_; 3710 my $report = ''; 3711 my $depsOK = 1; 3712 foreach my $dep ( @$deps ) { 3713 my ( $ok, $ver ) = ( 1, 0 ); 3714 my $msg = ''; 3715 my $const = ''; 3716 3717 eval "require $dep->{package}"; 3718 if ( $@ ) { 3719 $msg .= "it could not be found: $@"; 3720 $ok = 0; 3721 } else { 3722 if ( defined( $dep->{constraint} ) ) { 3723 $const = $dep->{constraint}; 3724 eval "\$ver = \$$dep->{package}::VERSION;"; 3725 if ( $@ ) { 3726 $msg .= "the VERSION of the package could not be found: $@"; 3727 $ok = 0; 3728 } else { 3729 eval "\$ok = ( \$ver $const )"; 3730 if ( $@ || ! $ok ) { 3731 $msg .= " $ver is currently installed: $@"; 3732 $ok = 0; 3733 } 3734 } 3735 } 3736 } 3737 unless ( $ok ) { 3738 $report .= "WARNING: $dep->{package}$const is required for $context, but $msg\n"; 3739 $depsOK = 0; 3740 } 3741 } 3742 return undef if( $depsOK ); 3743 3744 return $report; 3745} 3746 3747=pod 3748 3749#TWikiAPIHistory 3750---++ TWiki API History 3751 3752---+++ TWiki-2001-09-01 (Athens Release) 3753$TWiki::Plugins::VERSION 1.000 3754---++++ EmptyPlugin.pm 3755 * =commonTagsHandler($text, $topic, $web)= 3756 * =endRenderingHandler($text)= 3757 * =outsidePREHandler($text)= 3758 * =insidePREHandler($text)= 3759 * =startRenderingHandler($text, $web)= 3760---++++ Func.pm 3761 * =checkAccessPermission($type, $login, $topicText, $topicName, $webName) -> $boolean= 3762 * =expandCommonVariables($text, $topic, $web) -> $text= 3763 * =extractNameValuePair($attrs, $name) -> $value= 3764 * =formatGmTime($time) -> $text= 3765 * =getCgiQuery() -> $query= 3766 * =getDataDir() -> $dir= 3767 * =getDefaultUserName() -> $loginName= 3768 * =getMainWebname() -> $name= 3769 * =getOopsUrl($web, $topic, $template, @theParams) -> $url= 3770 * =getPreferencesFlag($key) -> $boolean= 3771 * =getPreferencesValue($key, $web) -> $value= 3772 * =getPublicWebList() -> @webs= 3773 * =getPubDir() -> $dir= 3774 * =getPubUrlPath() -> $path= 3775 * =getRevisionInfo($webName, $topic, $rev, $attachment) -> ($date, $user, $rev, $comment)= 3776 * =getScriptUrl($web, $topic, $script) -> $url= 3777 * =getScriptUrlPath() -> $path= 3778 * =getSessionValue($key) -> $value= 3779 * =getSkin() -> $skin= 3780 * =getTopicList($web) -> @topics= 3781 * =getTwikiWebname() -> $name= 3782 * =getUrlHost() -> $host= 3783 * =getViewUrl($web, $topic) -> $url= 3784 * =getWikiName() -> $wikiName= 3785 * =getWikiUserName($text) -> $wikiName= 3786 * =getWikiToolName() -> $name= 3787 * =internalLink($preamble, $web, $topic, $linkText, $anchor, $createLink) -> $text= 3788 * =isGuest() -> $boolean= 3789 * =permissionsSet($web) -> $boolean= 3790 * =readFile($filename) -> $text= 3791 * =readTemplate($name, $skin) -> $text= 3792 * =readTopic($webName, $topic) -> ($meta, $text)= 3793 * =redirectCgiQuery($query, $url)= 3794 * =renderText($text, $web) -> $text= 3795 * =saveFile($filename, $text)= 3796 * =setSessionValue($key, $value)= 3797 * =topicExists($web, $topic) -> $boolean= 3798 * =userToWikiName($user, $dontAddWeb) -> $wikiName= 3799 * =webExists($web) -> $boolean= 3800 * =wikiToUserName($wiki) -> $loginName= 3801 * =writeDebug($text)= 3802 * =writeHeader()= 3803 * =writeWarning($text)= 3804 3805---+++ TWiki-2003-02-01 (Beijing Release) 3806$TWiki::Plugins::VERSION 1.010 3807---++++ EmptyPlugin.pm 3808 * =afterEditHandler($text, $topic, $web)= 3809 * =beforeEditHandler($text, $topic, $web)= 3810 * =beforeSaveHandler($text, $topic, $web)= 3811 * =initializeUserHandler($loginName, $url, $pathInfo)= 3812 * =redirectCgiQueryHandler($query, $url)= 3813 * =registrationHandler($web, $wikiName, $loginName)= 3814 * =writeHeaderHandler($query)= 3815---++++ Func.pm 3816 * =checkTopicEditLock($web, $topic) ->($oopsUrl, $loginName, $unlockTime)= 3817 * =readTopicText($web, $topic, $rev, $ignorePermissions) -> $text= 3818 * =saveTopicText($web, $topic, $text, $ignorePermissions, $dontNotify) -> $oopsUrl= 3819 * =setTopicEditLock($web, $topic, $lock) -> $oopsUrl= 3820 3821---+++ TWiki-2004-09-02 (Cairo Release) 3822$TWiki::Plugins::VERSION 1.025 3823---++++ EmptyPlugin.pm 3824 * =afterCommonTagsHandler($text, $topic, $web)= 3825 * =afterSaveHandler($text, $topic, $web, $error)= 3826 * =beforeCommonTagsHandler($text, $topic, $web)= 3827 * =earlyInitPlugin()= 3828---++++ Func.pm 3829 * =afterAttachmentSaveHandler(\%attrHash, $topic, $web, $error, $meta)= 3830 * =beforeAttachmentSaveHandler(\%attrHash, $topic, $web, $meta)= 3831 * =checkDependencies($moduleName, $dependenciesRef) -> $error= 3832 * =extractParameters($attr) -> %params= 3833 * =formatTime($time, $format, $timezone) -> $text= 3834 * =getPluginPreferencesFlag($key) -> $boolean= 3835 * =getPluginPreferencesValue($key) -> $value= 3836 * =getRegularExpression($regexName) -> $pattern= 3837 3838---+++ TWiki-4.0.0 (Dakar Release) 3839$TWiki::Plugins::VERSION 1.1 3840---++++ EmptyPlugin.pm 3841 * =mergeHandler($diff, $old, $new, \%info) -> $text= 3842 * =modifyHeaderHandler(\%headers, $query)= 3843 * =postRenderingHandler($text)= 3844 * =preRenderingHandler($text, \%map)= 3845 * =renderFormFieldForEditHandler($name, $type, $size, $value, $attributes, $possibleValues) -> $html= 3846 * =renderWikiWordHandler($linkText, $hasExplicitLinkLabel, $web, $topic) -> $linkText= 3847 3848 * <strike> =endRenderingHandler($text)= </strike> 3849 * <strike> =startRenderingHandler($text, $web)= </strike> 3850---++++ Func.pm 3851 * =addToHEAD($id, $header)= 3852 * =attachmentExists($web, $topic, $attachment) -> $boolean= 3853 * =clearSessionValue($key) -> $boolean= 3854 * =checkDependencies($moduleName, $dependenciesRef) -> $error= 3855 * =createWeb($newWeb, $baseWeb, $opts)= 3856 * =expandTemplate($def ) -> $string= 3857 * =expandVariablesOnTopicCreation($text) -> $text= 3858 * =getContext() -> \%hash= 3859 * =getListOfWebs($filter) -> @webs= 3860 * =getScriptUrl($web, $topic, $script, @params) -> $url= 3861 * =getRevisionAtTime($web, $topic, $time) -> $rev= 3862 * =getWorkArea($pluginName) -> $directorypath= 3863 * =isValidWikiWord($text) -> $boolean= 3864 * =loadTemplate($name, $skin, $web) -> $text= 3865 * =moveAttachment($web, $topic, $attachment, $newWeb, $newTopic, $newAttachment)= 3866 * =moveTopic($web, $topic, $newWeb, $newTopic)= 3867 * =moveWeb($oldName, $newName)= 3868 * =normalizeWebTopicName($web, $topic) ->($web, $topic)= 3869 * =readAttachment($web, $topic, $name, $rev) -> $data= 3870 * =registerRESTHandler($alias, \&fn,)= 3871 * =registerTagHandler($var, \&fn, $syntax)= 3872 * =saveAttachment($web, $topic, $attachment, $opts)= 3873 * =saveTopic($web, $topic, $meta, $text, $options) -> $error= 3874 * =searchInWebContent($searchString, $web, \@topics, \%options) -> \%map= 3875 * =sendEmail($text, $retries) -> $error= 3876 * =wikiToEmail($wikiName) -> $email= 3877 * =writeHeader($query, $contentLength)= 3878 3879 * <strike> =checkDependencies($moduleName, $dependenciesRef) -> $error= </strike> 3880 * <strike> =formatGmTime($time, $format) -> $text= </strike> 3881 * <strike> =getDataDir() -> $dir= </strike> 3882 * <strike> =getOopsUrl( $web, $topic, $template, @params ) -> $url= </strike> 3883 * <strike> =getPubDir() -> $dir= </strike> 3884 * <strike> =getPublicWebList() -> @webs= </strike> 3885 * <strike> =getScriptUrlPath() -> $path= </strike> 3886 3887---+++ TWiki-4.0.1 (Dakar Patch Release) 3888$TWiki::Plugins::VERSION 1.1 3889---++++ EmptyPlugin.pm 3890 * =afterSaveHandler($text, $topic, $web, $error, $meta)= 3891 * =beforeSaveHandler($text, $topic, $web, $meta)= 3892---++++ Func.pm 3893 3894---+++ TWiki-4.1 (Edinburgh Release) 3895$TWiki::Plugins::VERSION 1.11 3896---++++ EmptyPlugin.pm 3897 * =afterRenameHandler($oldWeb, $oldTopic, $oldAttachment, $newWeb, $newTopic, $newAttachment)= 3898---++++ Func.pm 3899No changes 3900 3901---+++ TWiki-4.2 (Freetown Release) 3902$TWiki::Plugins::VERSION 1.2 3903---++++ EmptyPlugin.pm 3904 * =afterCommonTagsHandler($text, $topic, $web, $meta)= 3905 * =beforeCommonTagsHandler($text, $topic, $web, $meta)= 3906 * =commonTagsHandler($text, $topic, $web, $included, $meta)= 3907---++++ Func.pm 3908 * =decodeFormatTokens($str) -> $unencodedString= 3909 * =eachChangeSince($web, $time) -> $iterator= 3910 * =eachGroup() -> $iterator= 3911 * =eachGroupMember($group) -> $iterator= 3912 * =eachMembership($wikiname) -> $iterator= 3913 * =eachUser() -> $iterator= 3914 * =emailToWikiNames($email, $dontAddWeb) -> @wikiNames= 3915 * =expandCommonVariables($text, $topic, $web, $meta) -> $text= 3916 * =getCanonicalUserID( $user ) -> $cUID= 3917 * =getExternalResource($url) -> $response= 3918 * =getSessionKeys() -> @keys= 3919 * =isAnAdmin($login) -> $boolean= 3920 * =isGroup($group) -> $boolean= 3921 * =isGroupMember($group, $login) -> $boolean= 3922 * =isTrue($value, $default) -> $boolean= 3923 * =popTopicContext()= 3924 * =pushTopicContext($web, $topic)= 3925 * =sanitizeAttachmentName($fname) -> ($fileName, $origName)= 3926 * =setPreferencesValue($name, $val)= 3927 * =spaceOutWikiWord($word, $sep) -> $text= 3928 * =wikiNameToEmails($wikiname) -> @emails= 3929 * <strike> =permissionsSet($web) -> $boolean= </strike> 3930 * <strike> =getOopsUrl( $web, $topic, $template, $param1, $param2, $param3, $param4 ) -> $url= </strike> 3931 3932---+++ TWiki-4.3 (Georgetown Release) 3933$TWiki::Plugins::VERSION 1.2 3934---++++ EmptyPlugin.pm 3935No changes 3936---++++ Func.pm 3937No changes 3938 3939---+++ TWiki-5.0 (Helsinki Release) 3940$TWiki::Plugins::VERSION 1.3 3941---++++ EmptyPlugin.pm 3942No changes 3943---++++ Func.pm 3944 * =buildWikiWord( $text ) -> $text= 3945 3946---+++ TWiki-5.1 (Istanbul Release) 3947$TWiki::Plugins::VERSION 1.4 3948---++++ EmptyPlugin.pm 3949 * Callback function registered by =registerTagHandler= has two new parameters =$meta= and =$textRef= 3950---++++ Func.pm 3951 * =afterAttachmentSaveHandler(\%attrHash, $topic, $web, $error, $meta)= -- added =$meta= 3952 * =beforeAttachmentSaveHandler(\%attrHash, $topic, $web, $meta)= == added =$meta= 3953 * =writeLog( $action, $extra, $web, $topic, $user )= 3954 3955---+++ TWiki-6.0 (Jerusalem Release) 3956$TWiki::Plugins::VERSION 6.00 3957---++++ EmptyPlugin.pm 3958 * =viewRedirectHandler( $session, $web, $topic )= 3959---++++ Func.pm 3960 * =isAnAdmin( $user, $topic, $web ) -> $boolean= -- added =$topic= and =$web= 3961 * =expandVariablesOnTopicCreation( $text, $web, $topic ) -> $text= -- added =$web= and =$topic= 3962 * =postExternalResource( $url, $text, \@headers, \%params ) -> $response= 3963 * =registerExternalHTTPHandler( \&fn )= 3964 * =getContentMode( $web ) -> $contentMode= 3965 * =webWritable( $web ) -> $boolean= 3966 * =getDiskList() -> @diskIDs= 3967 * =getDiskInfo($web, $siteName) -> ($dataDir, $pubDir, $diskID)= 3968 * =trashWebName(web => $web | disk => $diskID) -> $trashWebName= 3969 * =entityEncode( $text, $extra ) -> $text= 3970 * =entityDecode( $text ) -> $text= 3971 * =urlEncode( $text ) -> $text= 3972 * =urlDecode( $text ) -> $text= 3973 3974---+++ TWiki-6.0.2 3975$TWiki::Plugins::VERSION 6.02 3976---++++ EmptyPlugin.pm 3977 * =viewFileRedirectHandler( $session, $web, $topic )= 3978 * =topicTitleHandler( $session, $web, $topic, $titleRef )= 3979 3980---+++ TWiki-6.0.3 3981$TWiki::Plugins::VERSION 6.10 3982---++++ Func.pm 3983 * =getDebugFilePath() -> $path= 3984 3985=cut 3986 39871; 3988