Attachment 'CreatePdfDocument2_1_5+p2.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 __doc__ = """
   3     MoinMoin - Generate PDF document using HTMLDOC
   4 
   5     This action script generate PDF documents from a Wiki site using
   6     the HTMLDOC (http://www.htmldoc.org) software packages which has
   7     to be preinstalled first.
   8 
   9     To use this feature install this script in your's MoinMoin action
  10     script plugin directory.
  11 
  12     Thanks goes to Pascal Bauermeister who initiated the implementaion.
  13     Lot of things changes since then but the idear using HTMLDOC is the
  14     main concept of this implementation.
  15 
  16     @copyright: (C) 2006  Pascal Bauermeister
  17     @copyright: (C) 2006-2007  Raphael Bossek
  18     @license: GNU GPL, see COPYING for details
  19 """
  20 
  21 __version__ = u'2.1.5+p2'
  22 
  23 release_information = """
  24 2007-09-24  RaphaelBossek
  25 * Release v2.1.5+p2
  26 * Fixed debug information for Windows.
  27 * This release is dedicated to find a Windows issue.
  28 * Set HTMLDOC_NOCGI envirionment variable.
  29 
  30 2007-09-23  RaphaelBossek
  31 * Release v2.1.5
  32 * Added support for line numbers in code blocks.
  33 * Remove page information so it's not printed for webpage style.
  34 * Added table cell padding to 5 pixels.
  35 
  36 2007-09-21  RaphaelBossek
  37 * Release v2.1.4
  38 * HTMLDOC supports only HTML 4.1 (http://www.htmldoc.org/documentation.php/Elements.html)
  39 * Fix for table borders and cell background.
  40 * Added support for code blocks (break on page boundries).
  41 
  42 2007-09-18  RaphaelBossek
  43 * Release v2.1.3
  44 * Added support for scaling images (--browserwidth).
  45 
  46 2007-08-21  RaphaelBossek
  47 * Release v2.1.2
  48 * Fixed support for python 2.3.
  49 
  50 2007-08-21  RaphaelBossek
  51 * Release v2.1.1
  52 * Applied speed improvemtn patch from BrianDickman.
  53 * Fixed font size values where x.9 was missing.
  54 * Some cosmetic changes in the form.
  55 
  56 2007-08-20  RaphaelBossek
  57 * Release v2.1.0
  58 * Configuration is seperated by tabbs.
  59 * Added support for font style and colors.
  60 * Fixed save/load of configuration variables within page (may be empty).
  61 
  62 2007-08-17  RaphaelBossek
  63 * Release v2.0.11
  64 * Added support for alternative title page and title page logo.
  65 * Added support for additional fields for the title page author, docnumber
  66   and copyright.
  67 
  68 2006-12-18  RaphaelBossek
  69 * Release v2.0.10
  70 * Improved support for webpage/book styles if the HTML documents does not.
  71 
  72 2006-12-17  RaphaelBossek
  73 * Release v2.0.9
  74 * Added AUTH_TYPE for RedirectOutputRequest()
  75 
  76 2006-11-16  RaphaelBossek
  77 * Release v2.0.8
  78 * Fixed another missing configuration for RedirectOutputRequest()
  79 
  80 2006-11-15  RaphaelBossek
  81 * Release v2.0.7
  82 * Fixed support for MoinMoin 1.5.3
  83 * Fixed SSL support.
  84 
  85 2006-11-14  RaphaelBossek
  86 * Release v2.0.6
  87 * MoinMoin 1.6 support added.
  88 * Fixed Windows(TM) platform support.
  89 * Added support for alternative title text.
  90 
  91 2006-09-13  RaphaelBossek
  92 * Release v2.0.5
  93 * Fixed RedirectOutputRequest class where definition of script_name
  94   was missing.
  95 
  96 2006-09-12  RaphaelBossek
  97 * Release v2.0.4
  98 * Fixed RedirectOutputRequest class where function was redifined
  99   to boolean value.
 100 
 101 2006-09-06  RaphaelBossek
 102 * Release v2.0.3
 103 * Fixed FastCGI support by removing stdout redirect output code. The
 104   same functionality will be done by the RedirectOutputRequest class.
 105 * Renamed to CreatePdfDocument (for better translation possibilities).
 106 * Fixed encoding of title page.
 107 * Added charset set option.
 108 * Fixed waiting for HTMLDOC.
 109 
 110 2006-09-02  RaphaelBossek
 111 * Release v2.0.2
 112 * Added createpdfdocument_validoptions and createpdfdocument_defaultvalues
 113   configuration parameter support. You are not able to preset available
 114   options and which defaults are used in your configuration file.
 115 
 116 2006-08-30  RaphaelBossek
 117 * Release v2.0.1
 118 * Fixed issue with page revision number forwarding (traceback).
 119 
 120 2006-08-30  RaphaelBossek
 121 * Release v2.0.0
 122 * Feature enchanced and bug fixed version.
 123 
 124 2006-05-26  PascalBauermeister
 125 * Release v1.0.2
 126 * Relative image URLs turned absolute was bogus. It is less bogus now.
 127 
 128 2006-05-26  PascalBauermeister
 129 * Release v1.0.1
 130 * Set env var HTMLDOC_NOCGI to solve CGI issue
 131 
 132 2006-05-24  PascalBauermeister
 133 * Initial release v1.0.0
 134 """
 135 
 136 import os
 137 import sys
 138 import stat
 139 import re
 140 import copy
 141 import shutil
 142 import StringIO
 143 import array
 144 from MoinMoin import config
 145 from MoinMoin import util
 146 from MoinMoin import wikiutil
 147 from MoinMoin import packages
 148 from MoinMoin import error
 149 from MoinMoin.Page import Page
 150 from MoinMoin.request import RequestBase
 151 from MoinMoin.widget.dialog import Dialog
 152 from MoinMoin.version import release as moinmoin_release
 153 
 154 # http://www.barelyfitz.com/projects/tabber/
 155 tabber_minimized = '''
 156 // Version 1.9 stripped by Creativyst SS & JavaScript Compressor v2.2c (http://www.creativyst.com/Prod/3/)
 157 function tabberObj(argsObj)
 158 { var arg; this.div = null; this.classMain = "tabber"; this.classMainLive = "tabberlive"; this.classTab = "tabbertab"; this.classTabDefault = "tabbertabdefault"; this.classNav = "tabbernav"; this.classTabHide = "tabbertabhide"; this.classNavActive = "tabberactive"; this.titleElements = ['h2','h3','h4','h5','h6']; this.titleElementsStripHTML = true; this.removeTitle = true; this.addLinkId = false; this.linkIdFormat = '<tabberid>nav<tabnumberone>'; for (arg in argsObj) { this[arg] = argsObj[arg];}
 159 this.REclassMain = new RegExp('\\\\b' + this.classMain + '\\\\b', 'gi'); this.REclassMainLive = new RegExp('\\\\b' + this.classMainLive + '\\\\b', 'gi'); this.REclassTab = new RegExp('\\\\b' + this.classTab + '\\\\b', 'gi'); this.REclassTabDefault = new RegExp('\\\\b' + this.classTabDefault + '\\\\b', 'gi'); this.REclassTabHide = new RegExp('\\\\b' + this.classTabHide + '\\\\b', 'gi'); this.tabs = new Array(); if (this.div) { this.init(this.div); this.div = null;}
 160 }
 161 tabberObj.prototype.init = function(e)
 162 { var
 163 childNodes, i, i2, t, defaultTab=0, DOM_ul, DOM_li, DOM_a, aId, headingElement; if (!document.getElementsByTagName) { return false;}
 164 if (e.id) { this.id = e.id;}
 165 this.tabs.length = 0; childNodes = e.childNodes; for(i=0; i < childNodes.length; i++) { if(childNodes[i].className &&
 166 childNodes[i].className.match(this.REclassTab)) { t = new Object(); t.div = childNodes[i]; this.tabs[this.tabs.length] = t; if (childNodes[i].className.match(this.REclassTabDefault)) { defaultTab = this.tabs.length-1;}
 167 }
 168 }
 169 DOM_ul = document.createElement("ul"); DOM_ul.className = this.classNav; for (i=0; i < this.tabs.length; i++) { t = this.tabs[i]; t.headingText = t.div.title; if (this.removeTitle) { t.div.title = '';}
 170 if (!t.headingText) { for (i2=0; i2<this.titleElements.length; i2++) { headingElement = t.div.getElementsByTagName(this.titleElements[i2])[0]; if (headingElement) { t.headingText = headingElement.innerHTML; if (this.titleElementsStripHTML) { t.headingText.replace(/<br>/gi," "); t.headingText = t.headingText.replace(/<[^>]+>/g,"");}
 171 break;}
 172 }
 173 }
 174 if (!t.headingText) { t.headingText = i + 1;}
 175 DOM_li = document.createElement("li"); t.li = DOM_li; DOM_a = document.createElement("a"); DOM_a.appendChild(document.createTextNode(t.headingText)); DOM_a.href = "javascript:void(null);"; DOM_a.title = t.headingText; DOM_a.onclick = this.navClick; DOM_a.tabber = this; DOM_a.tabberIndex = i; if (this.addLinkId && this.linkIdFormat) { aId = this.linkIdFormat; aId = aId.replace(/<tabberid>/gi, this.id); aId = aId.replace(/<tabnumberzero>/gi, i); aId = aId.replace(/<tabnumberone>/gi, i+1); aId = aId.replace(/<tabtitle>/gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); DOM_a.id = aId;}
 176 DOM_li.appendChild(DOM_a); DOM_ul.appendChild(DOM_li);}
 177 e.insertBefore(DOM_ul, e.firstChild); e.className = e.className.replace(this.REclassMain, this.classMainLive); this.tabShow(defaultTab); if (typeof this.onLoad == 'function') { this.onLoad({tabber:this});}
 178 return this;}; tabberObj.prototype.navClick = function(event)
 179 { var
 180 rVal, a, self, tabberIndex, onClickArgs; a = this; if (!a.tabber) { return false;}
 181 self = a.tabber; tabberIndex = a.tabberIndex; a.blur(); if (typeof self.onClick == 'function') { onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; if (!event) { onClickArgs.event = window.event;}
 182 rVal = self.onClick(onClickArgs); if (rVal === false) { return false;}
 183 }
 184 self.tabShow(tabberIndex); return false;}; tabberObj.prototype.tabHideAll = function()
 185 { var i; for (i = 0; i < this.tabs.length; i++) { this.tabHide(i);}
 186 }; tabberObj.prototype.tabHide = function(tabberIndex)
 187 { var div; if (!this.tabs[tabberIndex]) { return false;}
 188 div = this.tabs[tabberIndex].div; if (!div.className.match(this.REclassTabHide)) { div.className += ' ' + this.classTabHide;}
 189 this.navClearActive(tabberIndex); return this;}; tabberObj.prototype.tabShow = function(tabberIndex)
 190 { var div; if (!this.tabs[tabberIndex]) { return false;}
 191 this.tabHideAll(); div = this.tabs[tabberIndex].div; div.className = div.className.replace(this.REclassTabHide, ''); this.navSetActive(tabberIndex); if (typeof this.onTabDisplay == 'function') { this.onTabDisplay({'tabber':this, 'index':tabberIndex});}
 192 return this;}; tabberObj.prototype.navSetActive = function(tabberIndex)
 193 { this.tabs[tabberIndex].li.className = this.classNavActive; return this;}; tabberObj.prototype.navClearActive = function(tabberIndex)
 194 { this.tabs[tabberIndex].li.className = ''; return this;}; function tabberAutomatic(tabberArgs)
 195 { var
 196 tempObj, divs, i; if (!tabberArgs) { tabberArgs = {};}
 197 tempObj = new tabberObj(tabberArgs); divs = document.getElementsByTagName("div"); for (i=0; i < divs.length; i++) { if (divs[i].className &&
 198 divs[i].className.match(tempObj.REclassMain)) { tabberArgs.div = divs[i]; divs[i].tabber = new tabberObj(tabberArgs);}
 199 }
 200 return this;}
 201 function tabberAutomaticOnLoad(tabberArgs)
 202 { var oldOnLoad; if (!tabberArgs) { tabberArgs = {};}
 203 oldOnLoad = window.onload; if (typeof window.onload != 'function') { window.onload = function() { tabberAutomatic(tabberArgs);};} else { window.onload = function() { oldOnLoad(); tabberAutomatic(tabberArgs);};}
 204 }
 205 if (typeof tabberOptions == 'undefined') { tabberAutomaticOnLoad();} else { if (!tabberOptions['manualStartup']) { tabberAutomaticOnLoad(tabberOptions);}
 206 }
 207 '''
 208 
 209 tabber_minimized_css = '''
 210 <style type="text/css">
 211 /*--------------------------------------------------
 212   REQUIRED to hide the non-active tab content.
 213   But do not hide them in the print stylesheet!
 214   --------------------------------------------------*/
 215 .tabberlive .tabbertabhide {
 216  display:none;
 217 }
 218 
 219 /*--------------------------------------------------
 220   .tabber = before the tabber interface is set up
 221   .tabberlive = after the tabber interface is set up
 222   --------------------------------------------------*/
 223 .tabber {
 224 }
 225 .tabberlive {
 226  margin-top:1em;
 227 }
 228 
 229 /*--------------------------------------------------
 230   ul.tabbernav = the tab navigation list
 231   li.tabberactive = the active tab
 232   --------------------------------------------------*/
 233 ul.tabbernav
 234 {
 235  margin:0;
 236  padding: 3px 0;
 237  border-bottom: 1px solid #778;
 238  font: bold 12px Verdana, sans-serif;
 239 }
 240 
 241 ul.tabbernav li
 242 {
 243  list-style: none;
 244  margin: 0;
 245  display: inline;
 246 }
 247 
 248 ul.tabbernav li a
 249 {
 250  padding: 3px 0.5em;
 251  margin-left: 3px;
 252  border: 1px solid #778;
 253  border-bottom: none;
 254  background: #DDE;
 255  text-decoration: none;
 256 }
 257 
 258 ul.tabbernav li a:link { color: #448; }
 259 ul.tabbernav li a:visited { color: #667; }
 260 
 261 ul.tabbernav li a:hover
 262 {
 263  color: #000;
 264  background: #AAE;
 265  border-color: #227;
 266 }
 267 
 268 ul.tabbernav li.tabberactive a
 269 {
 270  background-color: #fff;
 271  border-bottom: 1px solid #fff;
 272 }
 273 
 274 ul.tabbernav li.tabberactive a:hover
 275 {
 276  color: #000;
 277  background: white;
 278  border-bottom: 1px solid white;
 279 }
 280 
 281 /*--------------------------------------------------
 282   .tabbertab = the tab content
 283   Add style only after the tabber interface is set up (.tabberlive)
 284   --------------------------------------------------*/
 285 .tabberlive .tabbertab {
 286  padding:5px;
 287  border:1px solid #aaa;
 288  border-top:0;
 289 
 290  /* If you don't want the tab size changing whenever a tab is changed
 291     you can set a fixed height */
 292 
 293  /* height:200px; */
 294 
 295  /* If you set a fix height set overflow to auto and you will get a
 296     scrollbar when necessary */
 297 
 298  /* overflow:auto; */
 299 }
 300 
 301 /* If desired, hide the heading since a heading is provided by the tab */
 302 .tabberlive .tabbertab h2 {
 303  display:none;
 304 }
 305 .tabberlive .tabbertab h3 {
 306  display:none;
 307 }
 308 
 309 /* Example of using an ID to set different styles for the tabs on the page */
 310 .tabberlive#tab1 {
 311 }
 312 .tabberlive#tab2 {
 313 }
 314 .tabberlive#tab2 .tabbertab {
 315  height:200px;
 316  overflow:auto;
 317 }
 318 </style>
 319 '''
 320 
 321 class RedirectOutputRequest(RequestBase):
 322     """Redirect output to string without HTTP headers."""
 323     def __init__ (self, req, action='print'):
 324         """Prepare a compatible request."""
 325         # 1.5,1.6:req.path_info = u'/RaphaelBossek/\xd6nologe' | u'/FrontPage'
 326         # after enconde() self.path_info = '/RaphaelBossek/\xd6nologe'
 327         self.path_info = req.path_info.encode(config.charset)
 328         # 1.5,1.6:query_string = req.query_string = u'action=CreatePdfDocument'
 329         self.query_string = 'action=' + action
 330         if isinstance(self.query_string, unicode):
 331             raise UnicodeError('self.query_string can not be of type UNICODE for python 2.3 compatibility reasons.')
 332         # 1.5,1.6:request_uri = req.request_uri = u'/FrontPage?action=CreatePdfDocument'
 333         self.request_uri = req.path_info.replace(req.query_string, self.query_string)
 334         # 1.5,1.6:url = req.url = u'localhost:8080/FrontPage?action=CreatePdfDocument'
 335         self.url = req.url.replace(req.query_string, self.query_string)
 336         # 1.5,1.6: Not all kinds of request support SSL.
 337         if 'is_ssl' in req.__dict__:
 338             self.is_ssl = req.is_ssl
 339         else:
 340             self.is_ssl = 0
 341         # 1.5,1.6: Not all kinds of request set env.
 342         self.env = {}
 343         if 'env' in req.__dict__:
 344             # 1.5,1.6: Do not copy env otherwise UNICODE encoding does not work right.
 345             #self._setup_vars_from_std_env(req.env)
 346             self.env['AUTH_TYPE'] = req.env.get('AUTH_TYPE', '')
 347         self.http_host = req.http_host
 348         self.http_user_agent = req.http_user_agent
 349         self.request_method = None
 350         self.saved_cookie = req.saved_cookie
 351         self.remote_addr = req.remote_addr
 352         self.script_name = getattr (req, u'script_name', u'')
 353 
 354         self.req = req
 355         RequestBase.__init__(self)
 356 
 357     def run(self, rev = None):
 358         """Start processing the document."""
 359         # 1.6:MoinMoin/request/__init__.py: Initialise action from environment variables not from form.
 360         self.action = 'print'
 361         if rev:
 362             self.form[u'rev'] = [rev]
 363         self.output_string = u''
 364         self.error_string = u''
 365         self.sent_headers = False
 366         self.failed = 0
 367         RequestBase.run(self)
 368         return (self.output_string, self.error_string)
 369 
 370     def http_headers (self, *args, **kw):
 371         """Used by MoinMoin 1.5.x instead of emit_http_headers()."""
 372         self.sent_headers = True
 373     
 374     def emit_http_headers(self, *args, **kw):
 375         """Used by MoinMoin 1.6.x instaed of http_headers()."""
 376         self.sent_headers = 1
 377 
 378     def fail (self, err):
 379         """Catch if a error occurs and save the message in our string."""
 380         RequestBase.fail (self, err)
 381         if not self.error_string:
 382             self.error_string = str(err)
 383 
 384     def write (self, *data):
 385         """Catch the document in our output_string."""
 386         if self.sent_headers:
 387             if self.failed:
 388                 self.error_string += data[0]
 389             else:
 390                 self.output_string += data[0]
 391 
 392     def flush(self):
 393         pass
 394 
 395 
 396 def attachment_fsname(attachment, page, request):
 397     """Return location of attament on the file system. current_page is the relative location
 398     where attachment is used.
 399     """
 400     from MoinMoin.action import AttachFile
 401     pagename, filename = AttachFile.absoluteName(attachment, page.page_name)
 402     #self.request.log("attachment_link: url %s pagename %s filename %s" % (url, pagename, filename))
 403     fname = wikiutil.taintfilename(filename)
 404     return AttachFile.getFilename(request, pagename, fname)
 405 
 406 
 407 def shell_quote(parameter):
 408     o = parameter
 409     for c in [u' ', u'(', u')']:
 410         o = o.replace(c, u'\\' + c)
 411     return o
 412 
 413 
 414 def getEditorName(request):
 415     """Return name of the last editor."""
 416     editorname = u''
 417     log = request.page._last_edited(request)
 418     if log:
 419         if request.cfg.show_hosts:
 420             title = " @ %s[%s]" % (log.hostname, log.addr)
 421         else:
 422             title = ""
 423         kind, info = log.getInterwikiEditorData(request)
 424         if kind in ['interwiki', 'email']:
 425             if log._usercache[log.userid].__dict__.get('aliasname', u''):
 426                 editorname = log._usercache[log.userid].aliasname
 427             else:
 428                 editorname = log._usercache[log.userid].name
 429         elif kind == 'ip':
 430             try:
 431                 idx = info.index('.')
 432             except ValueError:
 433                 idx = len(info)
 434             editorname = wikiutil.escape(info[:idx])
 435     return editorname
 436 
 437 
 438 def pipeCommand(cmdstr, input=None):
 439     child_stdin, child_stdout, child_stderr = os.popen3(cmdstr, u'b')
 440     try:
 441         if input:
 442             child_stdin.write(input)
 443         child_stdin.close()
 444     except:
 445         pass
 446 
 447     child_output = child_stdout.read()
 448     child_stdout.close()
 449 
 450     child_error = child_stderr.read()
 451     child_stderr.close()
 452 
 453     if os.name in ['posix', 'mac']:
 454         try:
 455             # REMARK: Otherwise we get <defunct> processes.
 456             os.wait()
 457         except OSError, e:
 458             # 10: No child processes.
 459             if e.errno != 10:
 460                 raise
 461     return (child_output, child_error)
 462 
 463 
 464 class CreatePdfDocument:
 465     """Implementation of the PDF document generator."""
 466 
 467     def __init__(self):
 468         self.action_name = self.__class__.__name__
 469         self.pagename = None
 470         self.request = None
 471         self._ = None
 472         self.debug = False
 473         self.msg = None
 474         self.errormsgsent = False
 475         self.default_values = {
 476             'style': u'webpage',
 477             'format': u'pdf13',
 478             'titlefileimage': u'',
 479             'linkstyle': u'underline',
 480             'headerleft': u't',
 481             'headermiddle': u'.',
 482             'headerright': u'D',
 483             'footerleft': u'.',
 484             'footermiddle': u'/',
 485             'footerright': u'.',
 486             'tocheaderleft': u'.',
 487             'tocheadermiddle': u't',
 488             'tocheaderright': u'.',
 489             'tocfooterleft': u'.',
 490             'tocfootermiddle': u'.',
 491             'tocfooterright': u'i',
 492             'bodycolor': u'FFFFFF',
 493             'bodyimage': u'',
 494             'textcolor': u'000000',
 495             'linkcolor': u'0000E0',
 496             'size': u'legal',
 497             'user-password': u'',
 498             'owner-password': u'',
 499             'toclevels': u'3',
 500             'grayscale': u'unchecked',
 501             'title': u'checked',
 502             'duplex': u'unchecked',
 503             'landscape': u'unchecked',
 504             'usersize': u'',
 505             'margintop': u'0.50in',
 506             'marginbottom': u'0.50in',
 507             'marginleft': u'1.00in',
 508             'marginright': u'0.50in',
 509             'no-toc': u'checked',
 510             'no-links': u'checked',
 511             'firstpage': u'p1',
 512             'jpeg': u'0',
 513             'compression': u'0',
 514             'pagemode': u'outline',
 515             'pagelayout': u'single',
 516             'firstpage': u'c1',
 517             'numbered': u'checked',
 518             'encryption': u'unchecked',
 519             'permissioncopy': u'checked',
 520             'permissionprint': u'checked',
 521             'permissionannotate': u'checked',
 522             'permissionmodify': u'checked',
 523             'charset': u'iso-8859-1',
 524             'debug': u'',
 525             'rev': 0,
 526             'extra-titledocnumber': u'',
 527             'extra-titleauthor': u'',
 528             'extra-titlecopyright': u'',
 529             'pageinfo': u'unchecked',
 530             'bodyfont': u'times',
 531             'headingfont': u'helvetica',
 532             'headfootfont': u'helvetica',
 533             'fontsize': u'11.0',
 534             'headfootsize': u'11.0',
 535             'fontspacing': u'1.2',
 536             'embedfonts': u'checked',
 537             'browserwidth': u'680',
 538             'extra-dynamiccodeblock': u'checked',
 539             'extra-codeblocklinenumbers': u'checked',
 540             'htmldoc_cmd': u'htmldoc',
 541         }
 542         # We have to know which values are checkboxes within the form. If a key does
 543         # not exists wihtin the form the corresponding checkbox is not checked.
 544         self.form_checkbox = []
 545         for key, value in self.default_values.items():
 546             if value in [u'checked', u'unchecked']:
 547                 self.form_checkbox += [key]
 548         self.contenttype = u'application/pdf'
 549 
 550     def error_msg(self, msg):
 551         """Display error message."""
 552         if not self.errormsgsent:
 553             # Backward compatiblity with MoinMoin 1.5.
 554             if Page.send_page.func_code.co_varnames[1] == 'request':
 555                 Page(self.request, self.pagename).send_page(self.request, msg=msg)
 556             else:
 557                 Page(self.request, self.pagename).send_page(msg=msg)
 558             self.errormsgsent = True
 559 
 560     def fixhtmlstr(self, str):
 561         """Convert utf-8 encoded multi-byte sequences into &#XXXX; format."""
 562         htmlstr = array.array('c')
 563         for c in str:
 564             if ord(c) >= 128:
 565                 htmlstr.fromstring('&#%d;' % ord(c))
 566             else:
 567                 htmlstr.fromstring(c)
 568         return htmlstr.tostring()
 569 
 570     def set_page_values(self):
 571         """Scan raw page for additional information relating PDF generation."""
 572         #pdflines = False
 573         for line in self.request.page.get_raw_body().split(u'\n'):
 574             if line[:6] == u'##pdf ' and len(line[6:]):
 575                 line = line[6:]
 576                 key = line.split()[0]
 577                 value = line[len(key) + 1:]
 578                 # Only accept known values/settings.
 579                 if key in self.default_values:
 580                     # Check if there are any restrictions for key.
 581                     if key in self.valid_options:
 582                         # Set only the value if the restrictions are confirmed.
 583                         valid_values = self.valid_options[key].keys()
 584                         if value in valid_values:
 585                             self.values[key] = value
 586                     else:
 587                         # There are no restrictions for value.
 588                         self.values[key] = value
 589             elif not line:
 590                 break
 591 
 592     def set_page_default_values(self):
 593         # We are not able to recognise if this string is part of a verbatim area.
 594         matchtoclvl = re.compile(r'^\[\[TableOfContents\(\s*(\d+)\s*\)\]\]')
 595         matchtoc = re.compile(r'^\[\[TableOfContents\(*\)*\]\]')
 596         toc = False
 597         for line in self.request.page.get_raw_body().split(u'\n'):
 598             if line[:10] == u'#language ' and not u'language' in self.values:
 599                 lang = self.make_isolang(line[10:])
 600                 if lang:
 601                     self.default_values[u'language'] = lang
 602             elif not u'toclevels' in self.values and not toc:
 603                 result = matchtoclvl.match(line)
 604                 if result:
 605                     toclevels = int(result.group(1).strip())
 606                     if toclevels > 4:
 607                         toclevels = 4
 608                     self.default_values[u'toclevels'] = str(toclevels)
 609                     toc = True
 610                 elif matchtoc.match(line):
 611                     toc = True
 612         # We assume if table-of-contents is used we intent to generate a book.
 613         if toc:
 614             # Do not change style if set manually or by configuration.
 615             self.default_values[u'style'] = self.default_values.get(u'style', u'book')
 616         # Do not generate a table of contents page.
 617         if self.default_values[u'style'] != u'book':
 618             # Do not change style if set manually or by configuration.
 619             self.default_values[u'no-toc'] = self.default_values.get(u'no-toc', u'unchecked')
 620  
 621     def _select (self, name, description=None):
 622         """Helper function to create a selection control."""
 623         str = u'<select name="%s" size="1">' % (name,)
 624         if not description:
 625             description = self.valid_options[name]
 626         keys = description.keys()
 627         keys.sort()
 628         for value in keys:
 629             if value == self.values[name]:
 630                 selected = u'selected'
 631             else:
 632                 selected = u''
 633             str += u'<option value="%s" %s>%s</option>' % (value, selected, description[value],)
 634         str += u'</select>'
 635         return str
 636 
 637     def _chooseformat (self, name):
 638         """Helper function to create left/middle/right selection controls."""
 639         str = u"""    <tr>
 640         <td class="label"><label>%s</label></td>
 641         <td><table>
 642                 <tr>
 643                     <td>%s</td>
 644                     <td>%s</td>
 645                 </tr>
 646                 <tr>
 647                     <td>%s</td>
 648                     <td>%s</td>
 649                 </tr>
 650                 <tr>
 651                     <td>%s</td>
 652                     <td>%s</td>
 653                 </tr>
 654             </table>
 655         </td>
 656         <td>%s</td>
 657     </tr>""" % (self.fields[u'label_' + name],
 658               self.fields[u'label_left'], self._select(name + u'left', self.valid_options[u'tocformats']),
 659               self.fields[u'label_middle'], self._select(name + u'middle', self.valid_options[u'tocformats']),
 660               self.fields[u'label_right'], self._select(name + u'right', self.valid_options[u'tocformats']),
 661               self.fields[u'help_' + name],)
 662         return str
 663 
 664     def makeform (self, errormsg=u''):
 665         self.fields = {
 666             'error': errormsg,
 667             'pagename': wikiutil.escape(self.pagename),
 668             'action': self.action_name,
 669             'version': __version__,
 670             'moinmoin_release': moinmoin_release,
 671 
 672             'label_input': self._(u'Input'),
 673             'label_output': self._(u'Output'),
 674             'label_page': self._(u'Page'),
 675             'label_tableofcontents': self._(u'Contents'),
 676             'label_pdf': self._(u'PDF'),
 677             'label_security': self._(u'Security'),
 678 
 679             'label_choose_style': self._(u'Choose style'),
 680             'help_choose_style': self._(u'book: Create a structured PDF document with headings, chapters, etc.') + u'<br/>' + \
 681                                  self._(u'webpage: Specifies that the HTML sources are unstructured (plain web pages.) A page break is inserted between each file or URL in the output.') + u'<br/>' + \
 682                                  self._(u'continuous: Specifies that the HTML sources are unstructured (plain web pages.) No page breaks are inserted between each file or URL in the output.'),
 683 
 684             'help_titletext': self._(u'Title of the document for the front page.'),
 685             
 686             'label_titlefileimage': self._(u'Title file/image'),
 687             'help_titlefileimage': self._(u'The title image or HTML page. These file has to be an attachments!'),
 688             
 689             'label_extra-titledocnumber': self._(u'Version'),
 690             'help_extra-titledocnumber': self._(u'Specify document version to be displayed on the title page.'),
 691             
 692             'label_extra-titleauthor': self._(u'Author'),
 693             'help_extra-titleauthor': self._(u'Intellectual property owner of this document.'),
 694             
 695             'label_extra-titlecopyright': self._(u'Copyright'),
 696             'help_extra-titlecopyright': self._(u'Copyright notice for this document.'),
 697             
 698             'label_pageinfo': self._(u'Apply page information'),
 699             'help_pageinfo': self._(u'Information about who and when modified the document are applied at the end.'),
 700             
 701             'label_format': self._(u'Output format'),
 702             'help_format': self._(u'Specifies the output format.'),
 703 
 704             'label_outputoptions': self._(u'Output options'),
 705             'label_grayscale': self._(u'Grayscale document'),
 706             'label_titlepage': self._(u'Title page'),
 707             'label_titletext': self._(u'Title'),
 708             'label_jpeg': self._(u'JPEG big images'),
 709             'label_compression': self._(u'Compression'),
 710 
 711             'label_no-toc': self._(u'Generate a table of contents'),
 712             'help_no-toc': self._(u''),
 713 
 714             'label_toclevels': self._(u'Limit the number of levels in the table-of-contents'),
 715             'help_toclevels': self._(u'Sets the number of levels in the table-of-contents.') + u' ' + self._(u'Empty for unlimited levels.'),
 716 
 717             'label_numbered': self._(u'Numbered headings'),
 718             'help_numbered': self._(u'Check to number all of the headings in the document.'),
 719 
 720             'label_toctitle': self._(u'Table-of-contents title'),
 721             'help_toctitle': self._(u'Sets the title for the table-of-contents.') + u' ' + self._(u'Empty for default title.'),
 722 
 723             'label_left': self._(u'Left'),
 724             'label_middle': self._(u'Middle'),
 725             'label_right': self._(u'Right'),
 726 
 727             'label_tocheader': self._(u'Header of table-of-contantes page'),
 728             'help_tocheader': self._(u'Sets the page header to use on table-of-contents pages.'),
 729 
 730             'label_tocfooter': self._(u'Footer of table-of-contantes page'),
 731             'help_tocfooter': self._(u'Sets the page footer to use on table-of-contents pages.'),
 732 
 733             'label_header': self._(u'Page header'),
 734             'help_header': self._(u'Sets the page header to use on body pages.'),
 735 
 736             'label_footer': self._(u'Page footer'),
 737             'help_footer': self._(u'Sets the page footer to use on body pages.'),
 738 
 739             'label_colors': self._(u'Colors'),
 740             'label_no-links': self._(u'Create HTTP links'),
 741             'help_no-links': self._(u'Enables generation of links in PDF files.'),
 742             
 743             'label_linkstyle': self._(u'Style of HTTP links'),
 744             'help_linkstyle': self._(u''),
 745 
 746             'label_linkcolor': self._(u'HTTP links color'),
 747             'help_linkcolor': self._(u'Sets the color of links.'),
 748             
 749             'label_bodycolor': self._(u'Body color'),
 750             'help_bodycolor': self._(u'Enter the HTML color for the body (background).'),
 751             
 752             'label_bodyimage': self._(u'Body image'),
 753             'help_bodyimage': self._(u'Enter the image file for the body (background). These file has to be an attachments!'),
 754             
 755             'label_textcolor': self._(u'Text color'),
 756             'help_textcolor': self._(u'Enter the HTML color for the text.'),
 757             
 758             'label_duplex': self._(u'2-Sided'),
 759             'help_duplex': self._(u'Specifies that the output should be formatted for double-sided printing.'),
 760 
 761             'label_landscape': self._(u'Landscape'),
 762 
 763             'label_choose_size': self._(u'Choose page size'),
 764             'help_choose_size': self._(u'Choose one of the predefined standard sizes or select user defined.'),
 765 
 766             'label_usersize': self._(u'User defined page size'),
 767             'help_usersize': self._(u'Specifies the page size using a standard name or in points (no suffix or ##x##pt), inches (##x##in), centimeters (##x##cm), or millimeters (##x##mm).'),
 768 
 769             'label_browserwidth': self._(u'Browser width'),
 770             'help_browserwidth': self._(u'Set the target browser width in pixels (400-1200). This determines the page scaling of images.'),
 771 
 772             'label_margin': self._(u'User defined margin'),
 773             'label_margintop': self._(u'Top'),
 774             'label_marginbottom': self._(u'Bottom'),
 775             'label_marginleft': self._(u'Left'),
 776             'label_marginright': self._(u'Right'),
 777             'help_margin': self._(u'Specifies the margin size using points (no suffix or ##x##pt), inches (##x##in), centimeters (##x##cm), or millimeters (##x##mm).') + u' ' + self._(u'Keep empty for default value.'),
 778 
 779             'label_pagemode': self._(u'Page mode'),
 780             'help_pagemode': self._(u'Controls the initial viewing mode for the document.') + u'<br/>' + self._(u'Document: Displays only the docuemnt pages.') + u'<br/>' + self._(u'Outline: Display the table-of-contents outline as well as the document pages.') + u'<br/>' + self._(u'Full-screen: Displays pages on the whole screen; this mode is used primarily for presentations.'),
 781 
 782             'label_pagelayout': self._(u'Page layout'),
 783             'help_pagelayout': self._(u'Controls the initial layout of document pages on the screen.') + u'<br/>' + self._(u'Single: Displays a single page at a time.') + u'<br/>' + self._(u'One column: Displays a single column of pages at a time.') + u'<br/>' + self._(u'Two column left/right: Display two columns of pages at a time; the first page is displayed in the left or right column as selected.'),
 784 
 785             'label_firstpage': self._(u'First page'),
 786             'help_firstpage': self._(u'Choose the initial page that will be shown.'),
 787 
 788             'label_encryption': self._(u'Encryption'),
 789             'help_encryptin': self._(u'Enables encryption and security features for PDF output.'),
 790             'label_permissions': self._(u'Permissions'),
 791             'help_permissions': self._(u'Specifies the document permissions.'),
 792 
 793             'label_permissionannotate': self._(u'Annotate'),
 794             'label_permissionprint': self._(u'Print'),
 795             'label_permissionmodify': self._(u'Modify'),
 796             'label_permissioncopy': self._(u'Copy'),
 797 
 798             'label_owner-password': self._(u'Owner password'),
 799             'help_owner-password': self._(u'Specifies the owner password to control who can change document permissions etc.') + u' ' + self._(u'If this field is left blank, a random 32-character password is generated so that no one can change the document.'),
 800 
 801             'label_user-password': self._(u'User password'),
 802             'help_user-password': self._(u'Specifies the user password to restrict viewing permissions on this PDF document.') + u' ' + self._(u'Empty for no encryption.'),
 803 
 804             'label_expert': self._(u'Expert'),
 805             'label_language': self._(u'Language translation'),
 806             'help_language': self._(u'Specify language to use for date and time format.'),
 807 
 808             'label_extra-dynamiccodeblock': self._(u'Dynamic code block'),
 809             'help_extra-dynamiccodeblock': self._(u'Shrink code blocks on page.'),
 810             
 811             'label_extra-codeblocklinenumbers': self._(u'Lines in code block'),
 812             'help_extra-codeblocklinenumbers': self._(u'Show line numbers for code blocks.'),
 813 
 814             'label_fonts': self._(u'Fonts'),
 815             'label_fontsize': self._(u'Base font size'),
 816             'help_fontsize': self._(u'Set the default size of text.'),
 817             'label_fontspacing': self._(u'Line spacing'),
 818             'help_fontspacing': self._(u'Set the spacing between lines of text.'),
 819             'label_bodyfont': self._(u'Body typeface'),
 820             'help_bodyfont': self._(u'Choose the default typeface (font) of text.'),
 821             'label_headingfont': self._(u'Heading typeface'),
 822             'help_headingfont': self._(u'Choose the default typeface (font) of headings.'),
 823             'label_headfootsize': self._(u'Header/Footer size'),
 824             'help_headfootsize': self._(u'Set the size of header and footer text.'),
 825             'label_headfootfont': self._(u'Header/Footer font'),
 826             'help_headfootfont': self._(u'Choose the font for header and footer text.'),
 827             'label_charset': self._(u'Charset set'),
 828             'help_charset': self._(u'Change the encoding of the text in document.'),
 829             'label_embedfonts': self._(u'Embed fonts'),
 830             'help_embedfonts': self._(u'Check to embed font in the output file.'),
 831             
 832             'label_about': self._(u'About'),
 833             'copyright': u'',
 834             'version': self._(u'Version') + u' ' + __version__,
 835 
 836             'button_generate': self._(u'Generate PDF'),
 837             'button_remember': self._(u'Remember form'),
 838             'button_cancel': self._(u'Cancel'),
 839             'button_reset': self._(u'Reset'),
 840             }
 841         
 842         self.fields['copyright'] = u"<br/>\n".join(wikiutil.escape(__doc__).split(u"\n"))
 843         self.fields.update(self.values)
 844 
 845         # Status of debug.
 846         if self.debug:
 847             self.fields[u'debug'] = u'1'
 848         else:
 849             self.fields[u'debug'] = u'0'
 850 
 851         # Go through all format strings.
 852         for name in [u'tocheader', u'tocfooter', u'header', u'footer']:
 853             self.fields[u'choose_' + name] = self._chooseformat(name)
 854 
 855         self.fields[u'select_style'] = self._select(u'style')
 856         self.fields[u'select_format'] = self._select(u'format')
 857         self.fields[u'select_linkstyle'] = self._select(u'linkstyle')
 858         self.fields[u'select_size'] = self._select(u'size')
 859         self.fields[u'select_jpeg'] = self._select(u'jpeg')
 860         self.fields[u'select_compression'] = self._select(u'compression')
 861         self.fields[u'select_toclevels'] = self._select(u'toclevels')
 862         self.fields[u'select_pagemode'] = self._select(u'pagemode')
 863         self.fields[u'select_pagelayout'] = self._select(u'pagelayout')
 864         self.fields[u'select_firstpage'] = self._select(u'firstpage')
 865         self.fields[u'select_charset'] = self._select(u'charset')
 866         self.fields[u'select_fontsize'] = self._select(u'fontsize')
 867         self.fields[u'select_bodyfont'] = self._select(u'bodyfont')
 868         self.fields[u'select_headingfont'] = self._select(u'headingfont')
 869         self.fields[u'select_headfootsize'] = self._select(u'headfootsize')
 870         self.fields[u'select_headfootfont'] = self._select(u'headfootfont')
 871         self.fields[u'select_fontspacing'] = self._select(u'fontspacing')
 872 
 873         # Add tabber implementation.
 874         self.request.cfg.html_head += """
 875 <script type="text/javascript">
 876 <!-- //
 877 %s
 878 //-->
 879 </script>
 880 
 881 %s
 882 """ % (tabber_minimized, tabber_minimized_css,)
 883 
 884         form = u''
 885         if self.debug:
 886             form += u'<p class="warning">Debug mode activated.</p>'
 887         if not moinmoin_release[:3] in [u'1.6', u'1.5']:
 888             form += u'<p class="warning">This plugin is not designed for MoinMoin %(moinmoin_release)s.</p>'
 889         form += """
 890 <p class="error">%(error)s</p>
 891 <form method="post" action="">
 892 <input type="hidden" name="action" value="%(action)s"/>
 893 <div class="tabber">
 894 <div class="tabbertab">
 895     <h3>%(label_input)s</h3>
 896     <table>
 897     <tr>
 898         <td class="label"><label>%(label_choose_style)s</label></td>
 899         <td class="content">%(select_style)s</td>
 900         <td>%(help_choose_style)s</td>
 901     </tr>
 902     <tr>
 903         <td class="label"><label>%(label_titletext)s</label></td>
 904         <td class="content"><input type="text" size="30" name="titletext" value="%(titletext)s" /></td>
 905         <td>%(help_titletext)s</td>
 906     </tr>
 907     <tr>
 908         <td class="label"><label>%(label_titlefileimage)s</label></td>
 909         <td class="content"><input type="text" size="30" name="titlefileimage" value="%(titlefileimage)s" /></td>
 910         <td>%(help_titlefileimage)s</td>
 911     </tr>
 912     <tr>
 913         <td class="label"><label>%(label_extra-titledocnumber)s</label></td>
 914         <td class="content"><input type="text" size="30" name="extra-titledocnumber" value="%(extra-titledocnumber)s" /></td>
 915         <td>%(help_extra-titledocnumber)s</td>
 916     </tr>
 917     <tr>
 918         <td class="label"><label>%(label_extra-titleauthor)s</label></td>
 919         <td class="content"><input type="text" size="30" name="extra-titleauthor" value="%(extra-titleauthor)s" /></td>
 920         <td>%(help_extra-titleauthor)s</td>
 921     </tr>
 922     <tr>
 923         <td class="label"><label>%(label_extra-titlecopyright)s</label></td>
 924         <td class="content"><input type="text" size="30" name="extra-titlecopyright" value="%(extra-titlecopyright)s" /></td>
 925         <td>%(help_extra-titlecopyright)s</td>
 926     </tr>
 927     <tr>
 928         <td class="label"><label>%(label_pageinfo)s</label></td>
 929         <td class="checkbox"><input type="checkbox" name="pageinfo" value="checked" %(pageinfo)s /></td>
 930         <td>%(help_pageinfo)s</td>
 931     </tr>
 932     </table>
 933 </div>
 934 <div class="tabbertab">
 935     <h3>%(label_output)s</h3>
 936     <table>
 937     <tr>
 938         <td class="label"><label>%(label_format)s</label></td>
 939         <td class="content">%(select_format)s</td>
 940         <td>%(help_format)s</td>
 941     </tr>
 942     <tr>
 943         <td class="label"><label>%(label_outputoptions)s</label></td>
 944         <td colspan="2"><input type="checkbox" name="grayscale" value="checked" %(grayscale)s />%(label_grayscale)s&nbsp;
 945             <input type="checkbox" name="title" value="checked" %(title)s />%(label_titlepage)s<br />
 946             %(label_compression)s&nbsp:&nbsp;%(select_compression)s&nbsp;
 947             %(label_jpeg)s&nbsp;%(select_jpeg)s</td>
 948     </tr>
 949     </table>
 950 </div>
 951 <div class="tabbertab">
 952     <h3>%(label_page)s</h3>
 953     <table>
 954     <tr>
 955         <td class="label"><label>%(label_choose_size)s</label></td>
 956         <td>%(select_size)s&nbsp;<br /><nobr>%(label_usersize)s&nbsp;<input type="text" size="15" name="usersize" value="%(usersize)s" /></nobr></td>
 957         <td>%(help_choose_size)s<br />%(help_usersize)s</td>
 958     </tr>
 959     <tr>
 960         <td class="label"><label>%(label_browserwidth)s</label></td>
 961         <td class="content"><input type="text" size="30" name="browserwidth" value="%(browserwidth)s" /></td>
 962         <td>%(help_browserwidth)s</td>
 963     </tr>
 964     <tr>
 965         <td>&nbsp;</td>
 966         <td colspan="2"><input type="checkbox" name="duplex" value="checked" %(duplex)s />&nbsp;%(label_duplex)s&nbsp;
 967             <input type="checkbox" name="landscape" value="checked" %(landscape)s />&nbsp;%(label_landscape)s</td>
 968     </tr>
 969     <tr>
 970         <td class="label"><label>%(label_margin)s</label></td>
 971         <td><table><tr><td>&nbsp;</td><td><nobr><label>%(label_margintop)s</label>&nbsp;<input type="text" name="margintop" value="%(margintop)s" size="7" /></nobr></td><td>&nbsp;</td></tr>
 972             <tr><td><nobr><label>%(label_marginleft)s</label>&nbsp;<input type="text" name="marginleft" value="%(marginleft)s" size="7" /></nobr></td><td>&nbsp;</td><td><nobr><label>%(label_marginright)s</label>&nbsp;<input type="text" name="marginright" value="%(marginright)s" size="7" /></nobr></td></tr>
 973             <tr><td>&nbsp;</td><td><nobr><label>%(label_marginbottom)s</label>&nbsp;<input type="text" name="marginbottom" value="%(marginbottom)s" size="7" /></nobr></td><td>&nbsp;</td></tr></table>
 974         <td>%(help_margin)s</td>
 975     </tr>
 976     %(choose_header)s
 977     %(choose_footer)s
 978     </table>
 979 </div>
 980 <div class="tabbertab">
 981     <h3>%(label_tableofcontents)s</h3>
 982     <table>
 983     <tr>
 984         <td class="label"><label>%(label_no-toc)s</label></td>
 985         <td class="checkbox"><input type="checkbox" name="no-toc" value="checked" %(no-toc)s /></td>
 986         <td>%(help_no-toc)s</td>
 987     </tr>
 988     <tr>
 989         <td class="label"><label>%(label_toclevels)s</label></td>
 990         <td class="content">%(select_toclevels)s</td>
 991         <td>%(help_toclevels)s</td>
 992     </tr>
 993     <tr>
 994         <td>&nbsp;</td>
 995         <td><input type="checkbox" name="numbered" value="checked" %(numbered)s />&nbsp;%(label_numbered)s</td>
 996         <td>%(help_numbered)s</td>
 997     </tr>
 998     <tr>
 999         <td class="label"><label>%(label_toctitle)s</label></td>
1000         <td class="content"><input type="text" size="30" name="toctitle" value="%(toctitle)s" /></td>
1001         <td>%(help_toctitle)s</td>
1002     </tr>
1003     %(choose_tocheader)s
1004     %(choose_tocfooter)s
1005     </table>
1006 </div>
1007 <div class="tabbertab">
1008     <h3>%(label_colors)s</h3>
1009     <table>
1010     <tr>
1011         <td class="label"><label>%(label_bodycolor)s</label></td>
1012         <td class="content"><input type="text" size="6" name="bodycolor" value="%(bodycolor)s" /></td>
1013         <td>%(help_bodycolor)s</td>
1014     </tr>
1015     <tr>
1016         <td class="label"><label>%(label_bodyimage)s</label></td>
1017         <td class="content"><input type="text" size="30" name="bodyimage" value="%(bodyimage)s" /></td>
1018         <td>%(help_bodyimage)s</td>
1019     </tr>
1020     <tr>
1021         <td class="label"><label>%(label_textcolor)s</label></td>
1022         <td class="content"><input type="text" size="6" name="textcolor" value="%(textcolor)s" /></td>
1023         <td>%(help_textcolor)s</td>
1024     </tr>
1025     <tr>
1026         <td class="label"><label>%(label_linkcolor)s</label></td>
1027         <td class="content"><input type="text" size="6" name="linkcolor" value="%(linkcolor)s" /></td>
1028         <td>%(help_linkcolor)s</td>
1029     </tr>
1030     <tr>
1031         <td class="label"><label>%(label_linkstyle)s</label></td>
1032         <td class="content">%(select_linkstyle)s</td>
1033         <td>%(help_linkstyle)s</td>
1034     </tr>
1035     <tr>
1036         <td class="label"><label>%(label_no-links)s</label></td>
1037         <td><input type="checkbox" name="no-links" value="checked" %(no-links)s /></td>
1038         <td>%(help_no-links)s</td>
1039     </tr>
1040     </table>
1041 </div>
1042 <div class="tabbertab">
1043     <h3>%(label_fonts)s</h3>
1044     <table>
1045     <tr>
1046         <td class="label"><label>%(label_fontsize)s</label></td>
1047         <td class="content">%(select_fontsize)s</td>
1048         <td>%(help_fontsize)s</td>
1049     </tr>
1050     <tr>
1051         <td class="label"><label>%(label_fontspacing)s</label></td>
1052         <td class="content">%(select_fontspacing)s</td>
1053         <td>%(help_fontspacing)s</td>
1054     </tr>
1055     <tr>
1056         <td class="label"><label>%(label_bodyfont)s</label></td>
1057         <td class="content">%(select_bodyfont)s</td>
1058         <td>%(help_bodyfont)s</td>
1059     </tr>
1060     <tr>
1061         <td class="label"><label>%(label_headingfont)s</label></td>
1062         <td class="content">%(select_headingfont)s</td>
1063         <td>%(help_headingfont)s</td>
1064     </tr>
1065     <tr>
1066         <td class="label"><label>%(label_headfootsize)s</label></td>
1067         <td class="content">%(select_headfootsize)s</td>
1068         <td>%(help_headfootsize)s</td>
1069     </tr>
1070     <tr>
1071         <td class="label"><label>%(label_headfootfont)s</label></td>
1072         <td class="content">%(select_headfootfont)s</td>
1073         <td>%(help_headfootfont)s</td>
1074     </tr>
1075     <tr>
1076         <td class="label"><label>%(label_charset)s</label></td>
1077         <td class="content">%(select_charset)s</td>
1078         <td>%(help_charset)s</td>
1079     </tr>
1080     <tr>
1081         <td class="label"><label>%(label_embedfonts)s</label></td>
1082         <td class="checkbox"><input type="checkbox" name="embedfonts" value="checked" %(embedfonts)s /></td>
1083         <td>%(help_embedfonts)s</td>
1084     </tr>
1085 </table>
1086 </div>
1087 <div class="tabbertab">
1088     <h3>%(label_pdf)s</h3>
1089     <table>
1090     <tr>
1091         <td class="label"><label>%(label_pagemode)s</label></td>
1092         <td class="content">%(select_pagemode)s</td>
1093         <td>%(help_pagemode)s</td>
1094     </tr>
1095     <tr>
1096         <td class="label"><label>%(label_pagelayout)s</label></td>
1097         <td class="content">%(select_pagelayout)s</td>
1098         <td>%(help_pagelayout)s</td>
1099     </tr>
1100     <tr>
1101         <td class="label"><label>%(label_firstpage)s</label></td>
1102         <td class="content">%(select_firstpage)s</td>
1103         <td>%(help_firstpage)s</td>
1104     </tr>
1105     </table>
1106 </div>
1107 <div class="tabbertab">
1108     <h3>%(label_security)s</h3>
1109     <table>
1110     <tr>
1111         <td class="label"><label>%(label_encryption)s</label></td>
1112         <td><input type="checkbox" name="encryption" value="checked" %(encryption)s /></td>
1113         <td>%(help_numbered)s</td>
1114     </tr>
1115     <tr>
1116         <td class="label"><label>%(label_permissions)s</label></td>
1117         <td><nobr><input type="checkbox" name="permissionprint" value="checked" %(permissionprint)s />&nbsp;%(label_permissionprint)s</nobr>&nbsp;
1118             <nobr><input type="checkbox" name="permissionmodify" value="checked" %(permissionmodify)s />&nbsp;%(label_permissionmodify)s</nobr><br />
1119             <nobr><input type="checkbox" name="permissioncopy" value="checked" %(permissioncopy)s />&nbsp;%(label_permissioncopy)s</nobr>&nbsp;
1120             <nobr><input type="checkbox" name="permissionannotate" value="checked" %(permissionannotate)s />&nbsp;%(label_permissionannotate)s</nobr></td>
1121         <td>%(help_permissions)s</td>
1122     </tr>
1123     <tr>
1124         <td class="label"><label>%(label_user-password)s</label></td>
1125         <td class="content"><input type="password" size="30" name="user-password" value="%(user-password)s" /></td>
1126         <td>%(help_user-password)s</td>
1127     </tr>
1128     <tr>
1129         <td class="label"><label>%(label_owner-password)s</label></td>
1130         <td class="content"><input type="password" size="30" name="owner-password" value="%(owner-password)s" /></td>
1131         <td>%(help_owner-password)s</td>
1132     </tr>
1133     </table>
1134 </div>
1135 <div class="tabbertab">
1136     <h3>%(label_expert)s</h3>
1137     <table>
1138     <tr>
1139         <td class="label"><label>%(label_language)s</label></td>
1140         <td class="content"><input type="text" size="6" name="language" value="%(language)s" /></td>
1141         <td>%(help_language)s</td>
1142     </tr>
1143     <tr>
1144         <td class="label"><label>%(label_extra-dynamiccodeblock)s</label></td>
1145         <td class="checkbox"><input type="checkbox" name="extra-dynamiccodeblock" value="checked" %(extra-dynamiccodeblock)s /></td>
1146         <td>%(help_extra-dynamiccodeblock)s</td>
1147     </tr>
1148     <tr>
1149         <td class="label"><label>%(label_extra-codeblocklinenumbers)s</label></td>
1150         <td class="checkbox"><input type="checkbox" name="extra-codeblocklinenumbers" value="checked" %(extra-codeblocklinenumbers)s /></td>
1151         <td>%(help_extra-codeblocklinenumbers)s</td>
1152     </tr>
1153     </table>
1154 </div>
1155 <div class="tabbertab">
1156     <h3>%(label_about)s</h3>
1157     <p>%(version)s (MoinMoin %(moinmoin_release)s)</p>
1158     <p>%(copyright)s</p>
1159 </div>
1160 </div>
1161 <p>
1162 <input type="hidden" name="debug" value="%(debug)s" /><input type="hidden" name="rev" value="%(rev)s" />
1163 <input type="submit" name="generate_from_form" value="%(button_generate)s" />&nbsp;
1164 <input type="submit" name="remember" value="%(button_remember)s" />&nbsp;
1165 <input type="submit" name="cancel" value="%(button_cancel)s" />&nbsp;
1166 </p>
1167 </form>
1168 """ % self.fields
1169         return Dialog(self.request, content=form)
1170 
1171     def run(self, pagename, request):
1172         """ Main dispatcher for the action."""
1173         self.pagename = pagename
1174         self.request = request
1175         self._ = self.request.getText
1176         self.form = self.request.form
1177         self.cfg = self.request.cfg
1178 
1179         # Canceled by user.
1180         if self.form.has_key(u'cancel'):
1181             # Backward compatiblity with MoinMoin 1.5.
1182             if Page.send_page.func_code.co_varnames[1] == "request":
1183                 return self.request.page.send_page(self.request)
1184             else:
1185                 return self.request.page.send_page()
1186 
1187         # Determine calling parameters.
1188         if self.form.get(u'debug', [u'0']) == [u'1']:
1189             self.debug = True
1190 
1191         # This dict contains all possible values.
1192         self.valid_options = {}
1193 
1194         self.valid_options[u'tocformats'] = {
1195             u'/': self._(u'1/N,2/N Arabic page numbers'),
1196             u':': self._(u'1/C,2/C Arabic chapter page numbers'),
1197             u'1': self._(u'1,2,3,...'),
1198             u'a': self._(u'a,b,c,...'),
1199             u'A': self._(u'A,B,C,...'),
1200             u'c': self._(u'Chapter title'),
1201             u'C': self._(u'Chapter page number'),
1202             u'd': self._(u'Date'),
1203             u'D': self._(u'Date + Time'),
1204             u'h': self._(u'Heading'),
1205             u'i': self._(u'i,ii,iii,iv,...'),
1206             u'I': self._(u'I,II,III,IV,...'),
1207             u't': self._(u'Title'),
1208             u'T': self._(u'Time'),
1209             u'.': self._(u'Blank'),
1210             # TODO: Not supported yet; u'l': self._(u'Logo image'),
1211         }
1212         self.valid_options[u'style'] = {
1213             u'webpage': self._(u'webpage'),
1214             u'book': self._(u'book'),
1215             u'continuous': self._(u'continuous'),
1216         }
1217         self.valid_options[u'size'] = {
1218             u'legal': self._(u'Legal (8.5x14in)'),
1219             u'a4': self._(u'A4 (210x297mm)'),
1220             u'letter': self._(u'Letter (8.5x11in)'),
1221             u'universal': self._(u'Universal (8.27x11in)'),
1222             u'': self._(u'User defined'),
1223         }
1224         self.valid_options[u'format'] = {
1225             u'pdf11': self._(u'PDF 1.1 (Acrobat 2.0)'),
1226             u'pdf12': self._(u'PDF 1.2 (Acrobat 3.0)'),
1227             u'pdf13': self._(u'PDF 1.3 (Acrobat 4.0)'),
1228             u'pdf14': self._(u'PDF 1.4 (Acrobat 5.0)'),
1229             # TODO: Not supported yet:
1230             #u'ps1': self._(u'PostScript Level 1'),
1231             #u'ps2': self._(u'PostScript Level 2'),
1232             #u'ps3': self._(u'PostScript Level 3'),
1233         }
1234         self.valid_options[u'linkstyle'] = {
1235             u'underline': self._(u'Underline'),
1236             u'plain': self._(u'Plain'),
1237         }
1238         self.valid_options[u'firstpage'] = {
1239             u'c1': self._(u'1st chapter'),
1240             u'p1': self._(u'1st page'),
1241             u'toc': self._(u'Contents'),
1242         }
1243         self.valid_options[u'jpeg'] = {
1244             u'0': self._(u'None'),
1245             u'50': self._(u' 50% (Good)'),
1246             u'55': u'55%', u' 60': u' 60%', u' 65': ' 65%', u' 70': ' 70%', u' 75': ' 75%',
1247             u'80': ' 80%', u' 85': ' 85%', u' 90': ' 90%', u' 95': ' 95%',
1248             u'100': self._(u'100% (Best)'),
1249         }
1250         self.valid_options[u'compression'] = {
1251             u'0': self._(u'None'),
1252             u'1': self._(u'1 (Fast)'),
1253             u'2': u'2', u'3': u'3', u'4': u'4', u'5': u'5', u'6': u'6', u'7': u'7', u'8': u'8',
1254             u'9': self._(u'9 (Best)'),
1255         }
1256         self.valid_options[u'toclevels'] = {
1257             u'0': self._(u'None'),
1258             u'1': u'1', u'2': '2', u'3': '3', u'4': '4'
1259         }
1260         self.valid_options[u'pagemode'] = {
1261             u'outline': self._(u'Outline'),
1262             u'document': self._(u'Document'),
1263             u'fullscreen': self._(u'Full-screen'),
1264         }
1265         self.valid_options[u'pagelayout'] = {
1266             u'single': self._(u'Single'),
1267             u'one': self._(u'One column'),
1268             u'twoleft': self._(u'Two column left'),
1269             u'tworight': self._(u'Two column right'),
1270         }
1271         self.valid_options[u'charset'] = {
1272             u'iso-8859-1': self._(u'ISO 8859-1'),
1273             u'iso-8859-2': self._(u'ISO 8859-2'),
1274             u'iso-8859-3': self._(u'ISO 8859-3'),
1275             u'iso-8859-4': self._(u'ISO 8859-4'),
1276             u'iso-8859-5': self._(u'ISO 8859-5'),
1277             u'iso-8859-6': self._(u'ISO 8859-6'),
1278             u'iso-8859-7': self._(u'ISO 8859-7'),
1279             u'iso-8859-8': self._(u'ISO 8859-8'),
1280             u'iso-8859-9': self._(u'ISO 8859-9'),
1281             u'iso-8859-14': self._(u'ISO 8859-14'),
1282             u'iso-8859-15': self._(u'ISO 8859-15'),
1283             u'cp-874': self._(u'cp-847'),
1284             u'cp-1250': self._(u'cp-1250'),
1285             u'cp-1251': self._(u'cp-1251'),
1286             u'cp-1252': self._(u'cp-1252'),
1287             u'cp-1253': self._(u'cp-1253'),
1288             u'cp-1254': self._(u'cp-1254'),
1289             u'cp-1255': self._(u'cp-1255'),
1290             u'cp-1256': self._(u'cp-1256'),
1291             u'cp-1257': self._(u'cp-1257'),
1292             u'cp-1258': self._(u'cp-1258'),
1293             u'koi-8r': self._(u'koi-8r'),
1294         }
1295         self.valid_options[u'bodyfont'] = {
1296             u'courier': self._(u'Courier'),
1297             u'helvetica': self._(u'Helvetica'),
1298             u'monospace': self._(u'Monospace'),
1299             u'sans': self._(u'Sans'),
1300             u'serif': self._(u'Serif'),
1301             u'times': self._(u'Times'),
1302         }
1303         self.valid_options[u'headingfont'] = self.valid_options[u'bodyfont']
1304         self.valid_options[u'headfootfont'] = self.valid_options[u'bodyfont']
1305         # Go through all font types and create fontname{-bold,-oblique,-boldoblique} entries.
1306         for fontname in self.valid_options[u'bodyfont'].keys():
1307             for fontstyle in [u'bold', u'oblique', u'boldoblique']:
1308                 self.valid_options[u'headfootfont'][fontname + u'-' + fontstyle] = u'%s (%s)' % (self.valid_options[u'headfootfont'][fontname], self._(fontstyle),)
1309         # Set possible font sizes.
1310         self._set_fontsize(u'headfootsize', 6, 24, 5)
1311         self._set_fontsize(u'fontsize', 4, 24, 5)
1312         self._set_fontsize(u'fontspacing', 1, 3, 1)
1313         
1314         # Set translated name of table of contents as default.
1315         self.default_values[u'toctitle'] = self._(u'Contents')
1316         
1317         self.default_values[u'titletext'] = self.pagename
1318         self.default_values[u'extra-titledocnumber'] = u'%d' % self.request.page.get_rev()[1]
1319         page_editor = self.request.page.lastEditInfo().get(u'editor', u'')
1320         self.default_values[u'extra-titleauthor'] = wikiutil.escape(getEditorName(self.request))
1321         
1322         # Make sure we create date and time strings in right format.
1323         if self.request.current_lang:
1324             self.default_values[u'language'] = self.request.current_lang
1325         elif self.request.page.language:
1326             self.default_values[u'language'] = self.request.page.language
1327         else:
1328             #self.cfg.language_default or "en"
1329             self.default_values[u'language'] = self.make_isolang(self.cfg.__dict__.get(u'default_language', u'en'))
1330 
1331         self.values = {}
1332 
1333         # If the configuration variable 'createpdfdocument_validoptions' exists we update our
1334         # self.valid_options dict with these values.
1335         if getattr (self.request.cfg, u'createpdfdocument_validoptions', None):
1336             self.valid_options.update (self.request.cfg.createpdfdocument_validoptions)
1337 
1338         # If the configuration variable 'createpdfdocument_defaultvalues' exists we update our
1339         # self.default_values dict with these values.
1340         if getattr (self.request.cfg, u'createpdfdocument_defaultvalues', None):
1341             for key, value in self.request.cfg.createpdfdocument_defaultvalues.items():
1342                 self.default_values[key] = value
1343         
1344         # Scan page to extract default values.
1345         self.set_page_default_values()
1346 
1347         # Create a PDF document direct without any user iteraction from default and page settings.
1348         if self.form.has_key(u'generate'):
1349             self.set_page_values()
1350             self.update_values(useform=False)
1351             return self.do_generate()
1352 
1353         # Create a PDF document from form settings.
1354         if self.form.has_key(u'generate_from_form'):
1355             self.update_values()
1356             return self.do_generate()
1357 
1358         if self.form.has_key(u'remember'):
1359             self.update_values()
1360             return self.do_remember()
1361 
1362         self.set_page_values()
1363         self.update_values(useform=False)
1364         # Backward compatiblity with MoinMoin 1.5.
1365         if Page.send_page.func_code.co_varnames[1] == 'request':
1366             return self.request.page.send_page(self.request, msg=self.makeform())
1367         else:
1368             return self.request.page.send_page(msg=self.makeform())
1369 
1370     def update_values (self, useform=True):
1371         """Preset values with they form values or defaults."""
1372         for key, default in self.default_values.items():
1373             # Modify value only if not already set.
1374             if not key in self.values:
1375                 # If the form does not contain the value (e.g. for checkboxes) set the
1376                 # default value (e.g. for checkboxes unset by default).
1377                 if not key in self.form:
1378                     # Special processing for checkboxes in forms. If the key does not exists
1379                     # within the form it is not checked.
1380                     if key in self.form_checkbox and useform:
1381                         self.values[key] = u'unchecked'
1382                     elif useform:
1383                         # Edit fields are missing if they are empty.
1384                         self.values[key] = u''
1385                     else:
1386                         self.values[key] = default
1387                 else:
1388                     self.values[key] = self.form[key][0]
1389         # Check if revision is an integer value.
1390         try:
1391             self.values[u'rev'] = int(self.values.get(u'rev', self.request.page.rev))
1392         except:
1393             self.values[u'rev'] = self.request.page.rev
1394         # Check if page revision exists.
1395         (pagefname, realrev, exists) = self.request.page.get_rev(rev=self.values[u'rev'])
1396         if exists:
1397             self.values[u'rev'] = realrev
1398         else:
1399             # Determine latest revision number.
1400             (pagefname, self.values[u'rev'], exists) = self.request.page.get_rev()
1401         # Check valid value range.
1402         try:
1403             self.values[u'browserwidth'] = int(self.values[u'browserwidth'])
1404             if self.values[u'browserwidth'] < 400 or self.values[u'browserwidth'] > 1200:
1405                 self.values[u'browserwidth'] = self.default_values[u'browserwidth']
1406         except:
1407             self.values[u'browserwidth'] = self.default_values[u'browserwidth']
1408         # We need a string.
1409         self.values[u'browserwidth'] = u'%s' % self.values[u'browserwidth']
1410 
1411     def do_generate (self):
1412         """Create PDF document."""
1413         # Generate the HTML page using MoinMoin wiki engine.
1414         html = self.get_html()
1415         if html:
1416             pdfdata = self.html2pdf(html)
1417             if pdfdata:
1418                 # Send as application/pdf the generated file by HTMLDOC
1419                 self.send_pdf(pdfdata)
1420                 
1421                 # MoinMoin1.6: send_closing_html() has to be called explicit.
1422                 # MoinMoin1.5: raise MoinMoinNoFooter exception to forbit creation of HTML footer.
1423                 if moinmoin_release[:3] == u'1.5':
1424                     from MoinMoin.util import MoinMoinNoFooter
1425                     raise MoinMoinNoFooter
1426 
1427     def do_remember(self):
1428         """Create a message containing information about how to save the form values for future reuse."""
1429         save = u''
1430         for key, value in self.values.items():
1431             if key in [u'user-password', u'owner-password', u'rev', u'debug']:
1432                 continue
1433             if key in self.default_values and value == self.default_values[key]:
1434                 continue
1435             save += u'##pdf %s %s' % (key, value,)
1436             if self.debug:
1437                 if key in self.default_values:
1438                     save += u' <-- default value is "%s" (without quotes)' % self.default_values[key]
1439                 else:
1440                     save += u' <-- keyword missing in defaults'
1441             save += u'\n'
1442         if save:
1443             msg = self._(u'Add follwing lines at the beginning of your page:') + u'<br/><pre>' + save + u'</pre>'
1444         else:
1445             msg = self._(u'All values correspond to they default. Nothing have to be saved.')
1446         # Backward compatiblity with MoinMoin 1.5.
1447         if Page.send_page.func_code.co_varnames[1] == "request":
1448             return self.request.page.send_page(self.request, msg)
1449         else:
1450             return self.request.page.send_page(msg)
1451 
1452     def send_pdf (self, data):
1453         """Send PDF file to HTTP server."""
1454         filename = self.pagename.replace (u'/', u'-') + u'-v' + str(self.values[u'rev']) + u'.pdf'
1455 
1456         # Send HTTP header.
1457         self.request.http_headers([
1458             'Content-Type: %s' % self.contenttype,
1459             'Content-Length: %d' % len(data),
1460             # TODO: fix the encoding here, plain 8 bit is not allowed
1461             # according to the RFCs There is no solution that is
1462             # compatible to IE except stripping non-ascii chars
1463             'Content-Disposition: inline; filename="%s"' % filename.encode(config.charset),
1464             ])
1465 
1466         # Send binary data.
1467         sio = StringIO.StringIO(data)
1468         shutil.copyfileobj(sio, self.request, 8192)
1469 
1470     def get_html (self):
1471         """Generate the HTML body of this page."""
1472         # Save page as HTML.
1473         newreq = RedirectOutputRequest(self.request)
1474         # Do not add edit information.
1475         # Add extra meta tags.
1476         orig_html_head = self.request.cfg.html_head
1477         self.request.cfg.html_head = self.request.cfg.html_head + u"""
1478 <meta name="docnumber" content="%s">
1479 <meta name="author" content="%s">
1480 <meta name="copyright" content="%s">
1481 """ % (wikiutil.escape(self.values['extra-titledocnumber']), wikiutil.escape(self.values['extra-titleauthor']), wikiutil.escape(self.values['extra-titlecopyright']),)
1482         (html, errmsg) = newreq.run(rev = self.values.get(u'rev', None))
1483         # Restore original HTML head configuration.
1484         self.request.cfg.html_head = orig_html_head
1485         if html:
1486             html = self.fixhtmlstr(html)
1487             # Make URLs absolute.
1488             # FIXME: Until MoinMoin is not XHTML compilant we can not use a XML parser
1489             # (e.g. expat) to transform the HTML document. In the meantime we try to
1490             # achive the same with regular expressions subtitution.
1491             base = self.request.getQualifiedURL()
1492             for htmlref in [u'src', u'href']:
1493                 reurlref = r'(%s=[\'"])(/[^\'"]*)[\'"]' % (htmlref,)
1494                 urlref = re.compile (reurlref, re.I)
1495                 for match in urlref.finditer(html):
1496                     foundref = match.groups()
1497                     html = html.replace (foundref[0] + foundref[1], foundref[0] + base + foundref[1])
1498 
1499             # Rename title of the document.
1500             titletext_html = self.fixhtmlstr(wikiutil.escape(self.values['titletext']))
1501             html = re.compile(r'<title>[^<]+</title>').sub(u'<title>%s</title>' % titletext_html, html)
1502 
1503             if self.values['pageinfo'] == u'unchecked':
1504                 # Remove pageinfo by regex. There is no standard way to do that yet.
1505                 # Read the comment in ThemeBase.shouldShowPageinfo().
1506                 html = re.compile(r'<p[^>]+id="pageinfo".*</p>').sub(u'', html)
1507             
1508             # HTMLDOC workarround: Add borders to tables. HTMLDOC assume border="0" if not defined.
1509             html = re.compile(r'<table>').sub(u'<table border="1" cellpadding="5">', html)
1510             
1511             # Display line numbers for code blocks without &middot;.
1512             if self.values[u'extra-dynamiccodeblock'] == u'checked':
1513                 if self.values[u'extra-codeblocklinenumbers'] == u'checked':
1514                     codeblocknr = re.compile(r'<span +class="LineNumber">([^<]+)</span>', re.IGNORECASE)
1515                     for match in codeblocknr.finditer(html):
1516                         newlinenr = u'<font color="%s">%s</font>' % (self.values[u'linkcolor'], match.group(1).replace(u' ', u'&nbsp;'),)
1517                         html = html.replace(match.group(0), newlinenr, 1)
1518                 else:
1519                     html = re.compile(r'<span +class="LineNumber">[^<]+</span>', re.IGNORECASE).sub(u'', html)
1520             
1521             # HTMLDOC: Does not support <span> so we remove them.
1522             for spanmatch in [r'<span[^>]*>', r'</span>']:
1523                 html = re.compile(spanmatch).sub(u'', html)
1524 
1525             # HTMLDOC: Does not support JavaScript
1526             html = re.compile(r'<script type="text/javascript">.*?</script>', re.IGNORECASE | re.DOTALL).sub(u'', html)
1527             
1528             # Remove page location added by &action=print.
1529             html = re.compile(r'<ul id="pagelocation">.*?</ul>', re.IGNORECASE | re.DOTALL).sub(u'', html)
1530             
1531             # HTMLDOC workarround: There is no CSS support in HTMLDOC.
1532             tablecolor = re.compile(r'<td.*?background-color: (#......).*?>')
1533             for match in tablecolor.finditer(html):
1534                 html = html.replace(match.group(0), u'<td bgcolor="%s">' % match.group(1), 1)
1535             
1536             # HTMLDOC workarround: Handle <pre> sections over page boundries.
1537             if self.values[u'extra-dynamiccodeblock'] == u'checked':
1538                 multiplespaces = re.compile(r'( {2,})')
1539                 for regexstr in [r'(<pre>)(.*?)(</pre>)', r'(<div class="codearea".*?>.*<pre.*?>)(.*?)(</pre>.*?</div>)']:
1540                     codesections = re.compile(regexstr, re.IGNORECASE | re.DOTALL)
1541                     for match in codesections.finditer(html):
1542                         foundref = match.groups()
1543                         presection = foundref[1]
1544                         # Search for multiple spaces and replace them by &middot; except the last space.
1545                         for spaces in multiplespaces.finditer(presection):
1546                             newspaces = u'&middot;' * (len(spaces.group(1)) - 1) + u' '
1547                             presection = presection.replace (spaces.group(1), newspaces, 1)
1548                         # Go through lines and add a &para; sign at the end of eatch line.
1549                         newprelines = []
1550                         prelines = presection.split(u"\n")
1551                         if len(prelines) > 1:
1552                             # For multiple lines we remove the last one.
1553                             for preline in prelines[:-1]:
1554                                 preline = preline + u'&para;<br />'
1555                                 newprelines.append(preline)
1556                         else:
1557                             newprelines = prelines
1558                         # Create a table arround an multi-line block.
1559                         if newprelines:
1560                             tablestart = u'<table border="1" bgcolor="#F3F5F7" cellpadding="5"><tr><td>'
1561                             tableend = u'</td></tr></table><br />'
1562                         else:
1563                             newprelines.append(preline)
1564                             tablestart = u''
1565                             tableend = u''
1566                         # Replace the <pre> block with new dynamic text.
1567                         html = html.replace(u''.join(foundref), u'%s<font face="Courier,Monospace">%s</font>%s' % (tablestart, u"\n".join(newprelines), tableend,), 1)
1568         else:
1569             self.error_msg(self._(u'Could not redirect HTML output for further processing:') + errmsg)
1570         return html
1571 
1572     def make_isolang (self, language):
1573         return language + u'_' + language.upper()
1574 
1575     def html2pdf (self, html):
1576         """Create a PDF document based on the current parameters."""
1577         # Set environment variables for HTMLDOC
1578         os.environ['LANG'] = self.values[u'language']
1579         os.environ['HTMLDOC_NOCGI'] = '1'
1580         # Determine UID to access ACL protected sites too (mandatory to download attached images).
1581         htmldocopts = [self.default_values['htmldoc_cmd'], "--cookies", "MOIN_ID=" + self.request.user.id, u'--no-duplex']
1582 
1583         for key in [u'header', u'footer', u'tocheader', u'tocfooter']:
1584             self.values[key] = self.values.get(key + u'left', u'.') + self.values.get(key + u'middle', u'.') + self.values.get(key + u'right', u'.')
1585 
1586         permissions = []
1587         for opt, value in self.values.items():
1588             # Skip alle non-HTMLDOC configuration parameters.
1589             if opt in [u'language', u'debug', u'rev', u'titletext', 'pageinfo', 'htmldoc_cmd'] or opt[:6] == u'extra-':
1590                 continue
1591             
1592             # Skip options without values.
1593             value = value.strip()
1594             if not value:
1595                 continue
1596             
1597             # Skip options for header/footer configuration which differenciate between position (e.g. footerright or tocheadermiddle)
1598             if opt[:6] in [u'header', u'footer'] and opt[6:] or opt[:9] in [u'tocheader', u'tocfooter'] and opt[9:]:
1599                 continue
1600             
1601             if opt == u'titlefileimage':
1602                 # Check if we have a --titlefile or --titleimage option.
1603                 lower_value = value.lower()
1604                 dotpos = lower_value.rfind(u'.')
1605                 if lower_value[dotpos:] in [u'.bmp', u'.gif', u'.jpg', u'.jpeg', u'.png']:
1606                     opt = u'titleimage'
1607                 else:
1608                     opt = u'titlefile'
1609                 value = attachment_fsname(value, self.request.page, self.request)
1610             elif opt == u'bodyimage':
1611                 value = attachment_fsname(value, self.request.page, self.request)
1612             
1613             if opt in [u'style']:
1614                 htmldocopts += [u'--' + value]
1615             elif opt in self.form_checkbox:
1616                 if value == u'checked':
1617                     if opt[:10] == u'permission':
1618                         permissions += [opt[10:]]
1619                     # Reverse meaning of 'no-' options.
1620                     elif opt[:3] != u'no-':
1621                         htmldocopts += [u'--' + opt]
1622                 elif opt[:3] == u'no-':
1623                     htmldocopts += [u'--' + opt]
1624             elif opt[:6] == u'margin':
1625                 htmldocopts += [u'--' + opt[6:], value]
1626             else:
1627                 htmldocopts += [u'--' + opt, value]
1628         if permissions:
1629             htmldocopts += [u'--permission', u','.join (permissions)]
1630         htmldocopts += [u'-']
1631         # Do not forget to escape all spaces!
1632         eschtmldocopts = [shell_quote(arg) for arg in htmldocopts]
1633         cmdstr = u' '.join(eschtmldocopts)
1634         errmsg = None
1635 
1636         pdf = None
1637         os.environ['HTMLDOC_NOCGI'] = '1'
1638         if self.debug:
1639             self.request.http_headers()
1640             errmsg = self._(u'HTMLDOC command:') + u'<pre>' + wikiutil.escape(cmdstr) + u'</pre>'
1641             cmdstr = self.default_values['htmldoc_cmd'] + u' --help'
1642             (htmldoc_help, htmldoc_err) = pipeCommand(cmdstr)
1643             errmsg += u'<p>Execute <tt>%s</tt><br /><pre>%s</pre></p>' % (wikiutil.escape(cmdstr), wikiutil.escape(htmldoc_help),)
1644             if 'env' in self.request.__dict__:
1645                 reqenv = u'%s' % wikiutil.escape(self.request.env)
1646             else:
1647                 reqenv = u'None'
1648             errmsg += u'<p>Python release %s<br />MoinMoin release <tt>%s</tt><br />CreatePdfDocument release <tt>%s</tt><br />self.request = <tt>%s</tt><br />self.request.env = <tt>%s</tt><br />os.environ = <tt>%s</tt></p>' % (wikiutil.escape(sys.version), wikiutil.escape(moinmoin_release), wikiutil.escape(__version__), wikiutil.escape(type(self.request)), wikiutil.escape(reqenv), wikiutil.escape(u"%s" % os.environ),)
1649             errmsg += u'<hr/><hr/><hr/>'
1650         else:
1651             (pdf, htmldocmsg) = pipeCommand(cmdstr, html)
1652 
1653             # Check for error message on STDOUT.
1654             if pdf[:8] == u'HTMLDOC ':
1655                 htmldocmsg += pdf
1656                 pdf = None
1657 
1658             if htmldocmsg:
1659                 errmsg = self._(u'Command:') + u'<pre>' + wikiutil.escape(cmdstr) + u'</pre>' + self._('returned:') + u'<pre>' + \
1660                       wikiutil.escape(htmldocmsg).replace(u'\n', u'<br/>') + u'</pre>'
1661 
1662         # As it is difficult to get the htmldoc return code, we check for
1663         # error by checking the produced pdf length
1664         if not pdf and errmsg:
1665             if self.debug:
1666                 self.request.write(u'<html><body>%s</body></hftml>' % errmsg)
1667                 self.request.write(html)
1668             else:
1669                 self.error_msg(errmsg)
1670         elif pdf[:4] != '%PDF':
1671             self.error_msg(self._(u'Invalid PDF document generated') + wikiutil.escape(pdf[:80]))
1672             pdf = None
1673         
1674         return pdf
1675 
1676     def _set_fontsize(self, key, min, max, smallstep):
1677         self.valid_options[key] = {}
1678         for fontsize_big in range(min, max):
1679             for fontsize_step in range(0, 10, smallstep):
1680                 fontsize = u'%d.%d' % (fontsize_big, fontsize_step,)
1681                 self.valid_options[key][fontsize] = self._(fontsize)
1682         self.valid_options[key][u'%d.0' % max] = self._(u'%d.0' % max)
1683 
1684 
1685 def execute (pagename, request):
1686     try:
1687         CreatePdfDocument().run (pagename = pagename, request = request)
1688     except:
1689         raise

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2008-06-25 06:31:28, 12.9 KB) [[attachment:AttributeError_form.html]]
  • [get | view] (2007-09-23 21:24:21, 74.0 KB) [[attachment:CreatePdfDocument2_1_5+p1.py]]
  • [get | view] (2007-09-24 19:04:02, 73.9 KB) [[attachment:CreatePdfDocument2_1_5+p2.py]]
  • [get | view] (2008-06-25 01:39:15, 77.3 KB) [[attachment:CreatePdfDocument2_3_0+p1.py]]
  • [get | view] (2008-06-25 06:52:21, 77.5 KB) [[attachment:CreatePdfDocument2_3_0+p2.py]]
  • [get | view] (2008-06-26 16:18:43, 81.0 KB) [[attachment:CreatePdfDocument2_3_0+p3.py]]
  • [get | view] (2008-11-10 06:53:43, 84.3 KB) [[attachment:CreatePdfDocument2_3_4+p1.py]]
  • [get | view] (2008-11-10 20:22:57, 84.7 KB) [[attachment:CreatePdfDocument2_3_4+p2.py]]
  • [get | view] (2009-01-12 19:30:53, 84.3 KB) [[attachment:CreatePdfDocument2_3_5+p1.py]]
  • [get | view] (2010-09-17 13:22:57, 86.4 KB) [[attachment:CreatePdfDocument2_4_1+p1.py]]
  • [get | view] (2010-05-16 05:14:41, 8311.5 KB) [[attachment:HTMLDOC_1.8.27.msi]]
  • [get | view] (2006-05-25 08:59:55, 100.6 KB) [[attachment:PdfAction--book.pdf]]
  • [get | view] (2006-05-25 10:37:23, 13.2 KB) [[attachment:PdfAction--page.pdf]]
  • [get | view] (2006-09-12 09:11:10, 8.3 KB) [[attachment:RedirectOutputRequest.html]]
  • [get | view] (2007-09-20 15:15:05, 10.9 KB) [[attachment:WikiAdministration_DebugInfo.zip]]
  • [get | view] (2007-09-24 06:25:51, 3.6 KB) [[attachment:WikiAdministration_DebugInfo_20070924.zip]]
  • [get | view] (2008-06-24 09:56:40, 16.0 KB) [[attachment:_AttributeError20080624.html]]
  • [get | view] (2006-09-11 18:56:44, 6.0 KB) [[attachment:bool.html]]
  • [get | view] (2007-06-28 20:42:45, 13.8 KB) [[attachment:coded_w_wing_large.png]]
  • [get | view] (2007-06-28 20:48:21, 8.6 KB) [[attachment:coded_w_wing_medium.png]]
  • [get | view] (2007-06-28 20:44:02, 6.8 KB) [[attachment:coded_w_wing_small.png]]
  • [get | view] (2008-06-26 17:18:39, 16.2 KB) [[attachment:debug260208.html]]
  • [get | view] (2007-09-20 15:14:47, 211.6 KB) [[attachment:htmldoc_WikiAdministration_ClassicTheme.zip]]
  • [get | view] (2008-12-21 10:40:28, 31.5 KB) [[attachment:listings.png]]
  • [get | view] (2010-09-16 12:23:08, 5.4 KB) [[attachment:moin.log.failed.gz]]
  • [get | view] (2010-09-16 12:23:22, 9.6 KB) [[attachment:moin.log.ok.gz]]
  • [get | view] (2014-08-18 02:10:25, 2.6 KB) [[attachment:patch_htmldoc_escaping.patch]]
  • [get | view] (2010-04-07 17:29:57, 5.7 KB) [[attachment:pdfbug.txt]]
  • [get | view] (2006-10-09 21:59:00, 0.7 KB) [[attachment:skip-one-region.diff]]
  • [get | view] (2008-12-21 10:33:05, 11.6 KB) [[attachment:traceback.html]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.