<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.yobi.be/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Fuujuhi</id>
	<title>YobiWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.yobi.be/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Fuujuhi"/>
	<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Special:Contributions/Fuujuhi"/>
	<updated>2026-04-28T00:17:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8571</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8571"/>
		<updated>2014-02-17T10:14:29Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* ChangeLog */ Say have a work-around for 0.5.1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
=== Example using templates ===&lt;br /&gt;
&lt;br /&gt;
The new syntax &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;...&amp;quot; [tag=&amp;quot;...&amp;quot;]&amp;gt;...&amp;amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; allows for using the RawFile extension in templates as well. &lt;br /&gt;
&lt;br /&gt;
The example below uses the template [[Template:Rawfiledownloadexample]] to avoid duplication between the file name in the text and as a parameter in the &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
See the template source for instructions on how to create the template.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code above gives&lt;br /&gt;
&amp;lt;hr/&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [https://www.mediawiki.org/wiki/Help:Magic_words magic words] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;code&amp;gt;anchor not found&amp;lt;/code&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the way MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
** Work-around available. See bugzilla bug report, or example section above.&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8570</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8570"/>
		<updated>2014-02-17T10:12:44Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Example using templates */ Match with style of other examples&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
=== Example using templates ===&lt;br /&gt;
&lt;br /&gt;
The new syntax &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;...&amp;quot; [tag=&amp;quot;...&amp;quot;]&amp;gt;...&amp;amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; allows for using the RawFile extension in templates as well. &lt;br /&gt;
&lt;br /&gt;
The example below uses the template [[Template:Rawfiledownloadexample]] to avoid duplication between the file name in the text and as a parameter in the &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
See the template source for instructions on how to create the template.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code above gives&lt;br /&gt;
&amp;lt;hr/&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [https://www.mediawiki.org/wiki/Help:Magic_words magic words] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;code&amp;gt;anchor not found&amp;lt;/code&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the way MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8569</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8569"/>
		<updated>2014-02-17T10:08:28Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Example using templates */ Remove redundant |}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
=== Example using templates ===&lt;br /&gt;
&lt;br /&gt;
The new syntax &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;...&amp;quot; [tag=&amp;quot;...&amp;quot;]&amp;gt;...&amp;amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; allows for using the RawFile extension in templates as well. &lt;br /&gt;
&lt;br /&gt;
An example of use is to create a template to avoid duplication between the file name in the text and as a parameter in the &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; tag. The example below uses the template [[Template:Rawfiledownloadexample]]. See the template source for instructions on how to create the template.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [https://www.mediawiki.org/wiki/Help:Magic_words magic words] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;code&amp;gt;anchor not found&amp;lt;/code&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the way MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8568</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8568"/>
		<updated>2014-02-17T10:08:08Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Example using templates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
=== Example using templates ===&lt;br /&gt;
&lt;br /&gt;
The new syntax &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;...&amp;quot; [tag=&amp;quot;...&amp;quot;]&amp;gt;...&amp;amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; allows for using the RawFile extension in templates as well. &lt;br /&gt;
&lt;br /&gt;
An example of use is to create a template to avoid duplication between the file name in the text and as a parameter in the &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;&amp;lt;/code&amp;gt; tag. The example below uses the template [[Template:Rawfiledownloadexample]]. See the template source for instructions on how to create the template.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [https://www.mediawiki.org/wiki/Help:Magic_words magic words] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;code&amp;gt;anchor not found&amp;lt;/code&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the way MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Template:Rawfiledownloadexample&amp;diff=8567</id>
		<title>Template:Rawfiledownloadexample</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Template:Rawfiledownloadexample&amp;diff=8567"/>
		<updated>2014-02-17T10:06:23Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Use name for the link as well&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can download file &amp;quot;{{{name}}}&amp;quot; below, just click this link: {{#tag:file|{{{name}}}|name={{{name}}}|tag=pre}}.&lt;br /&gt;
{{#tag:pre|{{{content}}}}}&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;hr/&amp;gt;&lt;br /&gt;
This is an example template to demonstrate how to use the RawFile extension tags in a template. &lt;br /&gt;
&lt;br /&gt;
The special construct &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#tag:file|...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is a work-around to a bug in mediawiki template expansion (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
See [[Mediawiki RawFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Template:Rawfiledownloadexample&amp;diff=8566</id>
		<title>Template:Rawfiledownloadexample</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Template:Rawfiledownloadexample&amp;diff=8566"/>
		<updated>2014-02-17T09:53:42Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can download file &amp;quot;{{{name}}}&amp;quot; below, just click this link: {{#tag:file|download|name={{{name}}}|tag=pre}}.&lt;br /&gt;
{{#tag:pre|{{{content}}}}}&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;hr/&amp;gt;&lt;br /&gt;
This is an example template to demonstrate how to use the RawFile extension tags in a template. &lt;br /&gt;
&lt;br /&gt;
The special construct &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#tag:file|...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is a work-around to a bug in mediawiki template expansion (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
See [[Mediawiki RawFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Template:Rawfiledownloadexample&amp;diff=8565</id>
		<title>Template:Rawfiledownloadexample</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Template:Rawfiledownloadexample&amp;diff=8565"/>
		<updated>2014-02-17T09:51:04Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: First version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can download file &amp;quot;{{{name}}}&amp;quot; below, just click this link: {{#tag:file|download|name={{{name}}}|tag=pre}}.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{{content}}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&amp;lt;hr/&amp;gt;&lt;br /&gt;
This is an example template to demonstrate how to use the RawFile extension tags in a template. &lt;br /&gt;
&lt;br /&gt;
The special construct &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#tag:file|...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is a work-around to a bug in mediawiki template expansion (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
See [[Mediawiki RawFile]] for more information.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
{{Rawfiledownloadexample|name=myfile.txt|content=Once upon a time&lt;br /&gt;
There was a Tag&lt;br /&gt;
Tag was clickable&lt;br /&gt;
And clicked it was}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8564</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8564"/>
		<updated>2014-02-14T08:11:06Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* ChangeLog */ Fix typos and font style&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [https://www.mediawiki.org/wiki/Help:Magic_words magic words] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;code&amp;gt;anchor not found&amp;lt;/code&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the way MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8563</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8563"/>
		<updated>2014-02-14T08:09:47Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* ChangeLog */ Fix broken link to mediawiki&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [https://www.mediawiki.org/wiki/Help:Magic_words magic words] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;tt&amp;gt;anchor not found&amp;lt;/tt&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the may MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8562</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8562"/>
		<updated>2014-02-14T08:05:52Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: v0.5.1 - Patch from Jani + prepare fix for &amp;#039;anchor not found&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    //Don&#039;t expand templates or we&#039;ll lose our anchors {{#...}}&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser, $frame ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText($parser-&amp;gt;recursiveTagParse( $args[&#039;title&#039;], $frame ));&lt;br /&gt;
&lt;br /&gt;
	//We expand templates, so &amp;lt;file&amp;gt; tag cannot be mixed with {{#fileanchor}} anchors&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;templates=expand&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;name&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;anchor&#039;], $frame ) );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $parser-&amp;gt;recursiveTagParse( $args[&#039;tag&#039;], $frame ) );&lt;br /&gt;
&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot;, $frame );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5.1&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5.1&#039;&#039;&#039;&lt;br /&gt;
* Integrate patch from Jani Uusitalo to recursively parse tag attribute values in case they contain [[mediawikiwiki:Help:Magic_words|magic words]] such as wiki templates or parameters. This is useful when using &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;gt;...&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates.&lt;br /&gt;
* Prepare fix for &amp;lt;tt&amp;gt;anchor not found&amp;lt;/tt&amp;gt; bug when using short notation &amp;lt;code&amp;gt;&amp;amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&amp;lt;/code&amp;gt; in wiki templates. This still doesn&#039;t work because of the may MediaWiki (v1.22.1) expands templates in raw output (see [https://bugzilla.wikimedia.org/show_bug.cgi?id=61341 bugzilla 61341]).&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions 0.4 and 0.4.1 are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
&amp;lt;!-- * [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki], website of [[User:Sicvolo|Alex Ivkin]] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://nginx.asia NGINX Asia] --&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://www.gnutelephony.org GNU Telephony] runs a fork of the extension: Fram --&amp;gt;&lt;br /&gt;
* [http://wiki.hpc.ufl.edu University of Florida Research Computing Wiki]&lt;br /&gt;
* [http://wiki.scribus.net Scribus wiki]&lt;br /&gt;
* [http://nfc-tools.org/ NFC-Tools]&lt;br /&gt;
* [https://smkent.net/wiki/ smkent.net], website of Stephen Kent&lt;br /&gt;
* [http://mummila.net/wiki/ mummila.net], website of Jani Uusitalo&lt;br /&gt;
* [http://www.richud.com/wiki/ richud.com], website of Richard Moore&lt;br /&gt;
&amp;lt;!-- * [http://risca.eu risca.eu], website of Riccardo Scartozzi&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;!-- * [http://far.no/fram/index.php?title=Fram Far.no/Fram], website of Haakon Meland Eriksen --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also wikiapiary to follow usage of extensions [https://wikiapiary.com/wiki/Extension:RawFile RawFile] and [https://wikiapiary.com/wiki/Extension:Fram Fram]&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8558</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8558"/>
		<updated>2014-02-13T15:31:40Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* ChangeLog */ Fix for MediaWiki 1.22.1 -- Official release 0.5&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $args[&#039;title&#039;] );&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $args[&#039;name&#039;] );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $args[&#039;anchor&#039;] );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $args[&#039;tag&#039;] );&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
* Fix for MediaWiki 1.22.1.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
* [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki] by [[User:Sicvolo|Sicvolo]]&lt;br /&gt;
* [http://far.no/fram/index.php?title=Fram Far.no/Fram]&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8557</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8557"/>
		<updated>2014-02-13T15:30:26Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Parser functions of the new tag &amp;amp;lt;file&amp;amp;gt; */ Fix for mw1.22.1 (UNIQxxxQINU tags appearing instead of file name)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, $parser ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $args[&#039;title&#039;] );&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $args[&#039;name&#039;] );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $args[&#039;anchor&#039;] );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $args[&#039;tag&#039;] );&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
* [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki] by [[User:Sicvolo|Sicvolo]]&lt;br /&gt;
* [http://far.no/fram/index.php?title=Fram Far.no/Fram]&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8556</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=8556"/>
		<updated>2014-02-13T15:29:14Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Credits */ Bump version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on Earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, &amp;amp;$parser ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $args[&#039;title&#039;] );&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $args[&#039;name&#039;] );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $args[&#039;anchor&#039;] );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $args[&#039;tag&#039;] );&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    // for backward compatibility, accept also URLs with parameter &#039;file&#039;&lt;br /&gt;
    if( $anchor==&#039;&#039; )&lt;br /&gt;
        $anchor=$_GET[&#039;file&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octet-stream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!s&#039;,&lt;br /&gt;
        function($m) { return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$m[0]); },&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.5&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.5&#039;&#039;&#039;&lt;br /&gt;
* Fix since PHP 5.5.0: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead. Thanks to Stephen Kent for reporting.&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&#039;&#039;&#039;WARNING&#039;&#039;&#039; you should upgrade ASAP as the previous versions are vulnerable to remote PHP code injection!!!&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;See [[Talk:Mediawiki_RawFile]] for more info.&lt;br /&gt;
&#039;&#039;&#039;0.4.1&#039;&#039;&#039;&lt;br /&gt;
* Fix octet-stream MIME type bug which was affecting Epiphany &amp;amp; Opera 11. Thanks to Jani Uusitalo for reporting &amp;amp; [[User:Sicvolo|Sicvolo]] for finding the solution&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name (differentiated by their anchor name) or even common blocks in multiple files.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;br /&gt;
==Known sites using the extension==&lt;br /&gt;
* [http://tech.ivkin.net/wiki/Main_Page Tech Knowledge Base Wiki] by [[User:Sicvolo|Sicvolo]]&lt;br /&gt;
* [http://far.no/fram/index.php?title=Fram Far.no/Fram]&lt;br /&gt;
* Well, this site of course! where I update the actual file on the server with a simple &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;wget -N --content-disposition &amp;quot;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=RawFile.php&amp;quot;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Talk:Mediawiki_RawFile&amp;diff=8555</id>
		<title>Talk:Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Talk:Mediawiki_RawFile&amp;diff=8555"/>
		<updated>2014-02-13T15:03:34Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Testing PHP code injection on Rawfile &amp;lt; 0.5 :&lt;br /&gt;
&amp;lt;br&amp;gt;Adding this code to a wikipage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;nowiki&amp;gt;{${phpinfo()}}&amp;lt;/nowiki&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
[{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
and trying to download myscript.sh will execute phpinfo() on the server.&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=6042</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=6042"/>
		<updated>2009-11-30T21:34:35Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Syntax */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;title=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, &amp;amp;$parser ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $args[&#039;title&#039;] );&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $args[&#039;name&#039;] );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $args[&#039;anchor&#039;] );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $args[&#039;tag&#039;] );&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octetstream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!se&#039;,&lt;br /&gt;
        &#039;preg_replace(&amp;quot;/\\\\\\\\\\\&#039;|./&amp;quot;,&amp;quot;X&amp;quot;,&amp;quot;$0&amp;quot;)&#039;,&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.4&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
Jani Uusitalo reported the following issue: &lt;br /&gt;
&amp;lt;br&amp;gt;For some reason, if you use Epiphany&#039;s &#039;Save as&#039; instead of a direct left-click, the downloaded file is a single byte. In Firefox the links work just fine, so this is probably an Epiphany bug. Uncommenting the &amp;lt;code&amp;gt;// wfResetOutputBuffers();&amp;lt;/code&amp;gt; line didn&#039;t help. If anyone knows a workaround to help Epiphany users without breaking the support of the other browsers, please speak up :-)&lt;br /&gt;
&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=6041</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=6041"/>
		<updated>2009-11-28T03:09:25Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Version 0.4 - new tag &amp;lt;file&amp;gt;, anchor using class attribute, error reporting, ignore &amp;lt;br&amp;gt; tag...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
The extension introduces 3 elements:&lt;br /&gt;
;Anchor&lt;br /&gt;
: Used to flag that the next code block in the wiki text belongs to a specific file. The code block can be any wiki block (such as &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;pre&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;code&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;tt&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;, &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;source&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;...). &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tags are ignored. Note that anchors are invisible in the wiki display.&lt;br /&gt;
;Link&lt;br /&gt;
: They are transformed by the extension into links that allows for downloading all blocks attached to a given anchor name.&lt;br /&gt;
;Anchor-link&lt;br /&gt;
: A shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor.&lt;br /&gt;
&lt;br /&gt;
The syntax is as follows. The syntax using tag &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; and tag attribute &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; is new since v0.4. Note that elements of both syntaxes can be mixed in a same page.&lt;br /&gt;
{| border=&amp;quot;2&amp;quot; cellspacing=&amp;quot;4&amp;quot; cellpadding=&amp;quot;3&amp;quot; style=&amp;quot;margin: 1em 1em 1em 0;  background: #f9f9f9; border: 1px #aaaaaa solid;  border-collapse: collapse;  empty-cells:show;&amp;quot;&lt;br /&gt;
!width=&amp;quot;80em&amp;quot; style=&amp;quot;background: #8da7d6;&amp;quot;|Element!!style=&amp;quot;background: #8da7d6;&amp;quot;|Syntax and description&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
{{#fileAnchor: anchorname}}&lt;br /&gt;
&amp;lt;pre class=&#039;anchorname&#039;&amp;gt;...&amp;amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code class=&amp;quot;cssclass anchorname&amp;quot;&amp;gt;...&amp;amp;lt;/code&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Indicates that the next wiki block is attached to an anchor &#039;&#039;anchorname&#039;&#039;. The content of that block will be downloaded (possibly appended with other blocks if there are several blocks attached to the same &#039;&#039;anchorname&#039;&#039;) when a file link is clicked on.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; To attach an anchor &#039;&#039;anchorname&#039;&#039; to a wiki block, simply add an attribute &amp;lt;code&amp;gt;class=&amp;quot;anchorname&amp;quot;&amp;lt;/code&amp;gt; to it. The extension supports multi-class specification, meaning that a same block can be associated to different files, and that the &amp;lt;code&amp;gt;class&amp;lt;/code&amp;gt; attribute can still be used to specify custom CSS properties as in standard wiki text.&lt;br /&gt;
; &#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
; class=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to which the wiki block is attached&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#fileLink: anchorname}} link text]&lt;br /&gt;
[{{#fileLink: anchorname|pagetitle}} link text]&lt;br /&gt;
&amp;lt;file anchor=&amp;quot;anchorname&amp;quot; [name=&amp;quot;filename&amp;quot;] [title=&amp;quot;pagetitle&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download all blocks that are attached to an anchor &#039;&#039;anchorname&#039;&#039;.&lt;br /&gt;
;&#039;&#039;anchorname&#039;&#039;&lt;br /&gt;
;anchor=&amp;quot;&#039;&#039;anchorname&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the anchor to look for. All blocks attached to an anchor &#039;&#039;anchorname&#039;&#039; will be downloaded.&lt;br /&gt;
;name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - Specifies the name of the file to download. If absent, &#039;&#039;anchorname&#039;&#039; is then used as the name of the downloaded file.&lt;br /&gt;
; &#039;&#039;pagetitle&#039;&#039;&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;pagetitle&#039;&#039;&amp;quot;&lt;br /&gt;
: &#039;&#039;Optional&#039;&#039; - Indicates that the blocks to download are on the wiki page titled &#039;&#039;pagetitle&#039;&#039;. If absent, blocks are looked for on the current page.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;Anchor-link&#039;&#039;&#039;&lt;br /&gt;
|&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
[{{#file: filename}} link text]&lt;br /&gt;
&amp;lt;file name=&amp;quot;filename&amp;quot; [tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;]&amp;gt;link text&amp;lt;/file&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Creates a link to download the next wiki block as a file named &#039;&#039;filename&#039;&#039;.&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;(since v0.4)&#039;&#039;&#039; The attribute &amp;lt;code&amp;gt;tag&amp;lt;/code&amp;gt; can be used to specify the &#039;&#039;tagname&#039;&#039; of the block to download.&amp;lt;br&amp;gt;&lt;br /&gt;
; &#039;&#039;filename&#039;&#039;&lt;br /&gt;
; name=&amp;quot;&#039;&#039;filename&#039;&#039;&amp;quot;&lt;br /&gt;
: The name of the file to download.&lt;br /&gt;
;tag=&amp;quot;&#039;&#039;tagname&#039;&#039;&amp;quot;&lt;br /&gt;
:&#039;&#039;Optional&#039;&#039; - When set, the extension only looks for blocks whose name matches the given &#039;&#039;tagname&#039;&#039;. This attribute is particularly useful when there are some irrelevant blocks between the &#039;&#039;&#039;anchor-link&#039;&#039;&#039; and the block you want to download. If absent, the first encountered block following the anchor is downloaded.&lt;br /&gt;
; &#039;&#039;link text&#039;&#039;&lt;br /&gt;
: The text of the link to display.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] or [http://www.mediawiki.org/wiki/Manual:Hooks/ParserFirstCallInit ParserFirstCallInit global hook] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
//Avoid unstubbing $wgParser on setHook() too early on modern (1.12+) MW versions, as per r35980&lt;br /&gt;
if ( defined( &#039;MW_SUPPORTS_PARSERFIRSTCALLINIT&#039; ) ) {&lt;br /&gt;
    $wgHooks[&#039;ParserFirstCallInit&#039;][] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
} else { // Otherwise do things the old fashioned way&lt;br /&gt;
    $wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
}&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, the parser functions &#039;&#039;&#039;file&#039;&#039;&#039; and &#039;&#039;&#039;fileLink&#039;&#039;&#039; are equally treated, while &#039;&#039;&#039;fileAnchor&#039;&#039;&#039; will be simply left out. We also create a new tag &#039;&#039;&#039;file&#039;&#039;&#039; as explained [http://www.mediawiki.org/wiki/Manual:Tag_extensions here].&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setHook( &#039;file&#039;, &#039;efRawFile_FileTagRender&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;anchor=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the new tag &amp;lt;tt&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/tt&amp;gt;===&lt;br /&gt;
The transformation rule to replace &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag to actual links for download. The same parser function is used for both &#039;&#039;&#039;anchors&#039;&#039;&#039; and &#039;&#039;&#039;anchor-links&#039;&#039;&#039;. Since the link text may contain wiki text, we generate the link as wiki text that we ask the parser to parse again.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_FileTagRender( $input, $args, &amp;amp;$parser ) {&lt;br /&gt;
    if( $args[&#039;title&#039;] == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $args[&#039;title&#039;] );&lt;br /&gt;
    $link=$title-&amp;gt;getFullURL( &#039;action=raw&#039; );&lt;br /&gt;
    if( $args[&#039;name&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;name=&#039;.urlencode( $args[&#039;name&#039;] );&lt;br /&gt;
    if( $args[&#039;anchor&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;anchor=&#039;.urlencode( $args[&#039;anchor&#039;] );&lt;br /&gt;
    if( $args[&#039;tag&#039;] != &#039;&#039; )&lt;br /&gt;
        $link.=&#039;&amp;amp;tag=&#039;.urlencode( $args[&#039;tag&#039;] );&lt;br /&gt;
    return $parser-&amp;gt;recursiveTagParse( &amp;quot;[$link $input]&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First we define a helper function that we will use to report error messages. This is simply done by replacing the content of the downloaded file with the error message and when necessary a copy of the raw text relevant to the error.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: Cancel the file download header and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip_Error($msg,$out,&amp;amp;$text) {&lt;br /&gt;
    $text=$msg;&lt;br /&gt;
    if($out != &#039;&#039;)&lt;br /&gt;
        $text.=&amp;quot;\nCandidate match: $out&amp;quot;;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    $filename=$_GET[&#039;name&#039;];&lt;br /&gt;
    $anchor=$_GET[&#039;anchor&#039;];&lt;br /&gt;
    $tag=$_GET[&#039;tag&#039;];&lt;br /&gt;
    // Either anchor or name must be specified&lt;br /&gt;
    if( $filename==&#039;&#039; )&lt;br /&gt;
        $filename=$anchor;&lt;br /&gt;
    if ( $filename==&#039;&#039; )&lt;br /&gt;
        return true;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octetstream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like &amp;lt;code&amp;gt;nowiki&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match). This is done with the scary regex below:&lt;br /&gt;
* we use &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; as pattern indicator so that the pattern string is self-matching. This is necessary since we will apply the extension on this page as well.&lt;br /&gt;
* we use option &amp;lt;code&amp;gt;s&amp;lt;/code&amp;gt; (multiline) and &amp;lt;code&amp;gt;e&amp;lt;/code&amp;gt; (evaluate replace expression)&lt;br /&gt;
* Evaluated expression replaces all characters in the matched string with X&#039;s. However if there are single quote (&amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt;) in the matched string, they will be escaped with &amp;lt;code&amp;gt;\&amp;lt;/code&amp;gt;. So we need to search for &amp;lt;code&amp;gt;\&#039;|.&amp;lt;/code&amp;gt;. The many back-slashes is because the expression is evaluated several times.&lt;br /&gt;
&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks?&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace(&#039;!&amp;lt;nowiki&amp;gt;.*?&amp;lt;/nowiki&amp;gt;!se&#039;,&lt;br /&gt;
        &#039;preg_replace(&amp;quot;/\\\\\\\\\\\&#039;|./&amp;quot;,&amp;quot;X&amp;quot;,&amp;quot;$0&amp;quot;)&#039;,&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors:&lt;br /&gt;
* If an anchor name is specified, we looked for &#039;&#039;&#039;all&#039;&#039;&#039; magic words &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileanchor:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or blocks with attribute &amp;lt;code&amp;gt;class=&amp;quot;[someclass ]anchorname&amp;quot;&amp;lt;/code&amp;gt; &lt;br /&gt;
* Otherwise we look for the first magic word &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file:...}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; with specified file name,&lt;br /&gt;
* And finally for the first &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; tag with the specified file name (no multiple blocks support)&lt;br /&gt;
And we free the memory used for the masked version&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (($anchor!=&#039;&#039;) &amp;amp;&amp;amp; preg_match_all(&#039;/({{#fileanchor: *&#039;.$anchor.&#039; *}})|(&amp;lt;[^&amp;gt;]+ class *= *&amp;quot;([^&amp;quot;]*\w)?&#039;.$anchor.&#039;(\w[^&amp;quot;]*)?&amp;quot;[^&amp;gt;]*&amp;gt;)/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$anchor.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else if (preg_match_all(&#039;/&amp;lt;file( [^&amp;gt;]*)? name *= *&amp;quot;&#039;.$filename.&#039;&amp;quot;[^&amp;gt;]*&amp;gt;/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else {&lt;br /&gt;
        // We didn&#039;t find our anchor&lt;br /&gt;
        return fnRawFile_Strip_Error(&amp;quot;ERROR - RawFile: anchor not found (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,&amp;quot;&amp;quot;,$text);&lt;br /&gt;
    }&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
We start from the position of the current anchor. If the tag name of the block attached to the anchor is not specified, we look for the first block that follows the anchor, excluding &amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; block. The search can be easily done with a regular expression, using the &#039;&#039;lookahead negative assertion&#039;&#039; &amp;lt;code&amp;gt;(?!br\b|file\b)&amp;lt;/code&amp;gt; to exclude the tags to ignore. Note that we need to ignore the anchor-link block &amp;lt;code&amp;gt;&amp;amp;lt;file&amp;amp;gt;&amp;lt;/code&amp;gt; since the anchor starts right before that tag, and so the regular expression would match the anchor-link block it that tag is not specifically excluded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        // If no tag specified, we take the first one&lt;br /&gt;
        if ($tag == &#039;&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            // With a regex assertion, we can easily ignore &#039;br&#039; and &#039;file&#039; tags&lt;br /&gt;
            if (!preg_match(&#039;/&amp;lt;((?!br\b|file\b)\w+\b)/&#039;, $out, $matches))&lt;br /&gt;
                return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: Can&#039;t find opening tag after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
            $tag=$matches[1];&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now, we know the tag name of the block to download, either because it was already specified as a GET attribute in the URL, or because we&#039;ve found it in the search above. Again, using a regular expression, we look for the first block matching the specified tag name that follows the current anchor, and extract the content of the blocks. Note the use of the regex option &amp;lt;code&amp;gt;/.../&amp;lt;u&amp;gt;s&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt; to tell the regex engine that the matched text can span on multiple lines (with that option, &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt; does match any character or a newline character). Also, we skip the first carriage return after the opening tag, if any (with &amp;lt;code&amp;gt;\n?&amp;lt;/code&amp;gt;).&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        // Find the first tag matching $tag, and return enclosed text&lt;br /&gt;
        if (!preg_match(&#039;/&amp;lt;&#039;.$tag.&#039;( [^&amp;gt;]*)?&amp;gt;\n?(.*?)&amp;lt;\/&#039;.$tag.&#039;&amp;gt;/s&#039;, $out, $matches))&lt;br /&gt;
            return fnRawFile_Strip_Error (&amp;quot;ERROR - RawFile: no closing &#039;$tag&#039; found after anchor &#039;$offset[0]&#039; (anchor=$anchor, name=$filename, tag=$tag)&amp;quot;,$out,$text);&lt;br /&gt;
        $text .= $matches[2];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.4&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen, Michael Peeters&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.4&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Anchors&#039;&#039;&#039; can be specified using html &#039;&#039;&#039;class&#039;&#039;&#039; attribute&lt;br /&gt;
* New syntax for &#039;&#039;&#039;Links&#039;&#039;&#039; and &#039;&#039;&#039;Anchor-links&#039;&#039;&#039;:&lt;br /&gt;
:&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;file [name=&amp;quot;...&amp;quot;] [anchor=&amp;quot;...&amp;quot;] [tag=&amp;quot;...&amp;quot;] [title=&amp;quot;...&amp;quot;] &amp;gt;Link text&amp;lt;/file&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* Support multiple files on the same page with same name.&lt;br /&gt;
* Can specify the tag name of the block to download (to skip some irrelevant blocks when using an &#039;&#039;&#039;anchor-link&#039;&#039;&#039;).&lt;br /&gt;
* Ignore &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;amp;lt;br&amp;amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039; tag.&lt;br /&gt;
* Some error reporting.&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
&lt;br /&gt;
==Known bugs==&lt;br /&gt;
Jani Uusitalo reported the following issue: &lt;br /&gt;
&amp;lt;br&amp;gt;For some reason, if you use Epiphany&#039;s &#039;Save as&#039; instead of a direct left-click, the downloaded file is a single byte. In Firefox the links work just fine, so this is probably an Epiphany bug. Uncommenting the &amp;lt;code&amp;gt;// wfResetOutputBuffers();&amp;lt;/code&amp;gt; line didn&#039;t help. If anyone knows a workaround to help Epiphany users without breaking the support of the other browsers, please speak up :-)&lt;br /&gt;
&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=5969</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=5969"/>
		<updated>2009-10-13T10:04:52Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Syntax */ There are actually 3 elements - merged the 3rd one in the list for clarity&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
There are 3 kinds of elements to add to the wiki language:&lt;br /&gt;
* anchors that will flag which code blocks belong to a specific file&lt;br /&gt;
** &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileAnchor: myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
** Not visible in the regular wiki display&lt;br /&gt;
* links that will allow to download the file&lt;br /&gt;
** &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileLink: myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
** or &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileLink: myscript.sh|Another Page}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
** The first syntax is used when the file is on the same page. It is transformed into new regular wikicode that will be eventually transformed to real URLs: &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{fullurl:{{PAGENAME}}|action=raw&amp;amp;file=myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=myscript.sh&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** The second syntax indicates that the file is on another local wiki page. It is eventually transformed into the real URLs: &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{fullurl:{{PAGENAME}}|action=raw&amp;amp;file=myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://wiki.yobi.be/index.php?title=Another_Page&amp;amp;action=raw&amp;amp;file=myscript.sh&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* a shortcut notation mixing both an anchor and download link, handy for regular use, when a single code block is used and when the download link can be at the same position as the anchor&lt;br /&gt;
** &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file: myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
$wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, file and fileLink are equally treated, while fileAnchor will be simply left out.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; )&lt;br /&gt;
        $title = $parser-&amp;gt;mTitle;&lt;br /&gt;
    else&lt;br /&gt;
        $title = Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;file=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    if (!isset($_GET[&#039;file&#039;]))&lt;br /&gt;
        return true;&lt;br /&gt;
    $filename=$_GET[&#039;file&#039;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octetstream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like nowiki.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks? &lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;/&amp;lt;nowiki&amp;gt;(.*?)&amp;lt;\/nowiki&amp;gt;/&#039;, &lt;br /&gt;
        create_function(&lt;br /&gt;
           &#039;$matches&#039;,&lt;br /&gt;
           &#039;return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$matches[0]);&#039;&lt;br /&gt;
        ),&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors (or the short version, in which case we only keep the first hit, no multiple blocks support)&lt;br /&gt;
&amp;lt;br&amp;gt;And we free the memory used for the masked version&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: instead of cowardly returning if we don&#039;t find our anchors, we should cancel the headers and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (preg_match_all(&#039;/{{#fileanchor: *&#039;.$filename.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$filename.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else&lt;br /&gt;
        // We didn&#039;t find our anchor, let&#039;s output all the raw...&lt;br /&gt;
        return true;&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Let&#039;s remove the text up to the tag following the anchor&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: the next tag could be a &amp;lt; br &amp;gt;, which we should skip&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        $out = substr($out, strpos($out, &#039;&amp;lt;&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
What type of tag do we have?&lt;br /&gt;
&amp;lt;br&amp;gt;Note that we&#039;re looking to the word directly following &#039;&amp;lt;&#039; up to &#039;&amp;gt;&#039; or a space, e.g. if there are arguments to the tag.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: once again, better handling of errors than just returning.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        if (!preg_match(&#039;/^&amp;lt;([^&amp;gt; ]+)/&#039;, $out, $matches))&lt;br /&gt;
            return true;&lt;br /&gt;
        $key = $matches[1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
OK, let&#039;s extract the text up to the closing tag&lt;br /&gt;
&amp;lt;br&amp;gt;We skip the first carriage return after the opening tag, if any&lt;br /&gt;
&amp;lt;br&amp;gt;We look for the closing tag and we take what&#039;s in between.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: once again, better handling of errors than just returning.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $begin = strpos($out, &#039;&amp;gt;&#039;)+1;&lt;br /&gt;
        if (ord(substr($out,$begin,1))==10)&lt;br /&gt;
            $begin++;&lt;br /&gt;
        if (preg_match_all(&#039;/&amp;lt;\/&#039;.$key.&#039;&amp;gt;/&#039;, $out, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
            $text .= substr($out, $begin, $matches[0][0][1]-$begin);&lt;br /&gt;
        else&lt;br /&gt;
            // error, we could not find end of bloc&lt;br /&gt;
            $text .= substr($out, $begin);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.3&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
==Known bugs==&lt;br /&gt;
Jani Uusitalo reported the following issue: &lt;br /&gt;
&amp;lt;br&amp;gt;For some reason, if you use Epiphany&#039;s &#039;Save as&#039; instead of a direct left-click, the downloaded file is a single byte. In Firefox the links work just fine, so this is probably an Epiphany bug. Uncommenting the &amp;lt;code&amp;gt;// wfResetOutputBuffers();&amp;lt;/code&amp;gt; line didn&#039;t help. If anyone knows a workaround to help Epiphany users without breaking the support of the other browsers, please speak up :-)&lt;br /&gt;
&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=5939</id>
		<title>Mediawiki RawFile</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;diff=5939"/>
		<updated>2009-09-21T22:13:45Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Adding optional parameter to #fileLink to indicate that the file is on a different local wiki page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Very short introduction==&lt;br /&gt;
Just have a look to the 2 [[Mediawiki_RawFile#Short_example|examples]] to see how to use the extension&lt;br /&gt;
&amp;lt;br&amp;gt;and to the [[Mediawiki_RawFile#Installation|Installation]] section to see how to install the extension in your [[MediaWiki]] server&lt;br /&gt;
==Introduction==&lt;br /&gt;
Originally the idea was to be able to download directly a portion of code as a file.&lt;br /&gt;
&amp;lt;br&amp;gt;I&#039;ve numerous code examples in my wiki and I wanted an easy way to download them, easier than a copy/paste!&lt;br /&gt;
&amp;lt;br&amp;gt;But from there it was rather easy to get something very close to [http://en.wikipedia.org/wiki/Literate_programming literate programming] just by allowing multiple blocks referring to the same file, which will be concatenated together at download time.&lt;br /&gt;
&lt;br /&gt;
* It must work with pre, nowiki, js, css, code, source, so let&#039;s make it general: take the tag that comes after the parser function we&#039;ll create and select data up to the closing tag.&lt;br /&gt;
* There are two distinct functionalities provided by the extension: &lt;br /&gt;
** the parser that will convert a magic word into a link to the download URL&lt;br /&gt;
** an extended ?action=raw that will strip the raw output to keep the desired code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
There are 2 kinds of elements to add to the wiki language:&lt;br /&gt;
* anchors that will flag which code blocks belong to a specific file&lt;br /&gt;
** &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileAnchor: myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
** Not visible in the regular wiki display&lt;br /&gt;
* links that will allow to download the file&lt;br /&gt;
** &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileLink: myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
** or &#039;&#039;&#039;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#fileLink: myscript.sh|Another Page}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
** The first syntax is used when the file is on the same page. It is transformed into new regular wikicode that will be eventually transformed to real URLs: &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{fullurl:{{PAGENAME}}|action=raw&amp;amp;file=myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://wiki.yobi.be/index.php?title=Mediawiki_RawFile&amp;amp;action=raw&amp;amp;file=myscript.sh&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
** The second syntax indicates that the file is on another local wiki page. It is eventually transformed into the real URLs: &amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{fullurl:{{PAGENAME}}|action=raw&amp;amp;file=myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://wiki.yobi.be/index.php?title=Another_Page&amp;amp;action=raw&amp;amp;file=myscript.sh&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For regular use, when a single code block is used and when the download link can be at the same position as the anchor, there is a shortcut notation mixing both anchor &amp;amp; link properties:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{#file: myscript.sh}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Short example===&lt;br /&gt;
The extension works with any block such as pre, nowiki, js, css, code, source,...&lt;br /&gt;
&amp;lt;br&amp;gt;This example is using the syntax highlighting &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt; tag provided by [http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi SyntaxHighlight extension] (using [http://qbnz.com/highlighter/ GeSHi Highlighter])&lt;br /&gt;
&amp;lt;br&amp;gt;If you didn&#039;t install that extension on your MediaWiki, you can try the example by using &amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt; instead of &amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s save the following code [{{#file: myscript.sh}} as myscript.sh]&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
echo &#039;Hello world!&#039;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Complete example===&lt;br /&gt;
And a full example with anchors &amp;amp; link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
will give:&lt;br /&gt;
----&lt;br /&gt;
Let&#039;s start with the Bash usual header:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll display a welcome message:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
echo &#039;Welcome on earth!&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And we finally exit cleanly:&lt;br /&gt;
{{#fileanchor: myotherscript.sh}}&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
exit 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[{{#filelink: myotherscript.sh}} myotherscript.sh is now available for download below the code]&lt;br /&gt;
&lt;br /&gt;
==The code (the ultimate example)==&lt;br /&gt;
Which you can of course download just by following [{{#filelink: RawFile.php}} this link :-)]&lt;br /&gt;
&lt;br /&gt;
So let&#039;s explain a bit the code in a Literate Programming way...&lt;br /&gt;
===Hooks===&lt;br /&gt;
First some hooks for our functions...&lt;br /&gt;
&lt;br /&gt;
We will create:&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Parser_functions Parser Function] (see also [http://meta.wikimedia.org/wiki/Help:Parser_function here]), with help of&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:%24wgExtensionFunctions $wgExtensionFunctions] to define the setup function&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Magic_words Magic Words]&lt;br /&gt;
** [http://www.mediawiki.org/wiki/Manual:Hooks/LanguageGetMagic LanguageGetMagic] hook to initialize the magic words&lt;br /&gt;
* a [http://www.mediawiki.org/wiki/Manual:Hooks/RawPageViewBeforeOutput RawPageViewBeforeOutput] hook to intercept the raw output&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
if (defined(&#039;MEDIAWIKI&#039;)) {&lt;br /&gt;
&lt;br /&gt;
$wgExtensionFunctions[] = &#039;efRawFile_Setup&#039;;&lt;br /&gt;
$wgHooks[&#039;LanguageGetMagic&#039;][]       = &#039;efRawFile_Magic&#039;;&lt;br /&gt;
$wgHooks[&#039;RawPageViewBeforeOutput&#039;][] = &#039;fnRawFile_Strip&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Setup function===&lt;br /&gt;
For the wiki parsing to create download links, file and fileLink are equally treated, while fileAnchor will be simply left out.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Setup() {&lt;br /&gt;
    global $wgParser;&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;file&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;filelink&#039;, &#039;efRawFile_Render&#039; );&lt;br /&gt;
    $wgParser-&amp;gt;setFunctionHook( &#039;fileanchor&#039;, &#039;efRawFile_Empty&#039; );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to initialize the magic words===&lt;br /&gt;
We add the magic words here: the first array element indicates if it is case sensitive, in this case it is not case sensitive. We could add extra elements to create synonyms for our parser function.&lt;br /&gt;
&amp;lt;br&amp;gt;Unless we return true, other parser functions extensions will not get loaded.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Magic( &amp;amp;$magicWords, $langCode ) {&lt;br /&gt;
    $magicWords[&#039;file&#039;] = array( 0, &#039;file&#039; );&lt;br /&gt;
    $magicWords[&#039;filelink&#039;] = array( 0, &#039;filelink&#039; );&lt;br /&gt;
    $magicWords[&#039;fileanchor&#039;] = array( 0, &#039;fileanchor&#039; );&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Parser functions of the magic words===&lt;br /&gt;
The transformation rule to replace link shortcuts to actual links for download, handling an optional local wiki page title if present.&lt;br /&gt;
&amp;lt;br&amp;gt;The input parameters are wikitext with templates expanded, the output should be wikitext too&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: what error to send out if there is no filename given?&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;EDIT&#039;&#039;&#039;: It seems that [http://svn.wikimedia.org/viewvc/mediawiki?view=rev&amp;amp;revision=27667 commit 27667] (1.11 -&amp;gt; 1.12) changed the default parser, which breaks the recursive parsing. Thanks to Tim Starling for helping me to get around the problem!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Render( &amp;amp;$parser, $filename = &#039;&#039;, $titleText = &#039;&#039;) {&lt;br /&gt;
    if( $titleText == &#039;&#039; ) {&lt;br /&gt;
        $titleText = $parser-&amp;gt;mTitle-&amp;gt;getText();&lt;br /&gt;
    }&lt;br /&gt;
    $title=Title::newFromText( $titleText );&lt;br /&gt;
    return $title-&amp;gt;getFullURL( &#039;action=raw&amp;amp;file=&#039;.urlencode( $filename ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And the other one, just removing the anchors from the rendered wiki page.&lt;br /&gt;
&amp;lt;br&amp;gt;Curiously enough if the function doesn&#039;t exist at all the effect is exactly the same, MW doesn&#039;t throw any error.&lt;br /&gt;
&amp;lt;br&amp;gt;But let&#039;s keep things clean...&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function efRawFile_Empty( &amp;amp;$parser, $filename = &#039;&#039;) {&lt;br /&gt;
    return &#039;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Hook to intercept the raw output===&lt;br /&gt;
This part of the code doesn&#039;t look that nice because we&#039;ve to parse the raw wiki page ourselves to retrieve the code sections we want.&lt;br /&gt;
&lt;br /&gt;
First let&#039;s see if &amp;lt;code&amp;gt;?action=raw&amp;lt;/code&amp;gt; was used in the context of this extension: in that case we receive the filename as GET parameter, otherwise we simply return from our extension with return value=true which means we authorize the raw display (originally the hook was created to add an authentication point)&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
function fnRawFile_Strip(&amp;amp;$rawPage, &amp;amp;$text) {&lt;br /&gt;
    if (!isset($_GET[&#039;file&#039;]))&lt;br /&gt;
        return true;&lt;br /&gt;
    $filename=$_GET[&#039;file&#039;];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
By default the downloadable file will still be handled by the ob_gzhandler session made by Mediawiki. To avoid output buffering and gzipping, one can uncomment the following line:&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    // Uncomment the following line to avoid output buffering and gzipping:&lt;br /&gt;
    // wfResetOutputBuffers();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Raw action already set the headers with some client cache pragmas and is supposed to be displayed in the browser but in our case we want to make this &amp;quot;page&amp;quot; a downloadable file so we overwrite the headers which were defined and we add a few more, to ensure there is no caching on the client (it&#039;s very hard for the client to force a refresh on a file download, contrary to a web page) and to provide the adequate filename.&lt;br /&gt;
&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    header(&amp;quot;Content-disposition: attachment;filename={$filename}&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Content-type: application/octetstream&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Content-Transfer-Encoding: binary&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Expires: 0&amp;quot;);&lt;br /&gt;
    header(&amp;quot;Pragma: no-cache&amp;quot;); &lt;br /&gt;
    header(&amp;quot;Cache-Control: no-store&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Then we&#039;ll strip the output, first we&#039;ve to locate the anchors but there are anchors that could be protected in literal blocks like nowiki.&lt;br /&gt;
&amp;lt;br&amp;gt;So we&#039;ll mask the literal blocks before searching for the anchors (we mask with the same string length because we&#039;ll retrieve an offset that we will use on the initial string and offsets must match)&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: should we care also of source, js, css, pre,... blocks? &lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $maskedtext=preg_replace_callback(&#039;/&amp;lt;nowiki&amp;gt;(.*?)&amp;lt;\/nowiki&amp;gt;/&#039;, &lt;br /&gt;
        create_function(&lt;br /&gt;
           &#039;$matches&#039;,&lt;br /&gt;
           &#039;return ereg_replace(&amp;quot;.&amp;quot;,&amp;quot;X&amp;quot;,$matches[0]);&#039;&lt;br /&gt;
        ),&lt;br /&gt;
        $text);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Now we can search for the anchors (or the short version, in which case we only keep the first hit, no multiple blocks support)&lt;br /&gt;
&amp;lt;br&amp;gt;And we free the memory used for the masked version&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: instead of cowardly returning if we don&#039;t find our anchors, we should cancel the headers and return a proper error page&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    if (preg_match_all(&#039;/{{#fileanchor: *&#039;.$filename.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=$matches[0];&lt;br /&gt;
    else if (preg_match_all(&#039;/{{#file: *&#039;.$filename.&#039; *}}/i&#039;, $maskedtext, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
        $offsets=array($matches[0][0]);&lt;br /&gt;
    else&lt;br /&gt;
        // We didn&#039;t find our anchor, let&#039;s output all the raw...&lt;br /&gt;
        return true;&lt;br /&gt;
    unset($maskedtext);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
$text is both input &amp;amp; output so we copy it and start with an empty output.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    $textorig=$text;&lt;br /&gt;
    $text=&#039;&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
For each anchor found we&#039;ve to isolate the content of the next block.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    foreach ($offsets as $offset) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Let&#039;s remove the text up to the tag following the anchor&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: the next tag could be a &amp;lt; br &amp;gt;, which we should skip&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $out = substr($textorig, $offset[1]);&lt;br /&gt;
        $out = substr($out, strpos($out, &#039;&amp;lt;&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
What type of tag do we have?&lt;br /&gt;
&amp;lt;br&amp;gt;Note that we&#039;re looking to the word directly following &#039;&amp;lt;&#039; up to &#039;&amp;gt;&#039; or a space, e.g. if there are arguments to the tag.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: once again, better handling of errors than just returning.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        if (!preg_match(&#039;/^&amp;lt;([^&amp;gt; ]+)/&#039;, $out, $matches))&lt;br /&gt;
            return true;&lt;br /&gt;
        $key = $matches[1];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
OK, let&#039;s extract the text up to the closing tag&lt;br /&gt;
&amp;lt;br&amp;gt;We skip the first carriage return after the opening tag, if any&lt;br /&gt;
&amp;lt;br&amp;gt;We look for the closing tag and we take what&#039;s in between.&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;&#039;TODO&#039;&#039;&#039;: once again, better handling of errors than just returning.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
        $begin = strpos($out, &#039;&amp;gt;&#039;)+1;&lt;br /&gt;
        if (ord(substr($out,$begin,1))==10)&lt;br /&gt;
            $begin++;&lt;br /&gt;
        if (preg_match_all(&#039;/&amp;lt;\/&#039;.$key.&#039;&amp;gt;/&#039;, $out, $matches, PREG_OFFSET_CAPTURE))&lt;br /&gt;
            $text .= substr($out, $begin, $matches[0][0][1]-$begin);&lt;br /&gt;
        else&lt;br /&gt;
            // error, we could not find end of bloc&lt;br /&gt;
            $text .= substr($out, $begin);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;No need to deal with a Content-Length header because Mediawiki will do it for us, moreover more properly than we could if the output is sent gzipped, which is the default.&lt;br /&gt;
&amp;lt;br&amp;gt;So that&#039;s it, $text contains our file!&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Credits===&lt;br /&gt;
There is an official way to register the extension in a Mediawiki installation, so that it will be visible on the [[Special:Version]] page.&lt;br /&gt;
&amp;lt;br&amp;gt;Let&#039;s say the extension is in the category of parser hooks even if there is also a hook on Raw action.&lt;br /&gt;
{{#fileanchor: RawFile.php}}&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
$wgExtensionCredits[&#039;parserhook&#039;][] = array(&#039;name&#039; =&amp;gt; &#039;RawFile&#039;,&lt;br /&gt;
                           &#039;version&#039; =&amp;gt; &#039;0.3&#039;,&lt;br /&gt;
                           &#039;author&#039; =&amp;gt; &#039;Philippe Teuwen&#039;,&lt;br /&gt;
                           &#039;url&#039; =&amp;gt; &#039;http://www.mediawiki.org/wiki/Extension:RawFile&#039;,&lt;br /&gt;
//                         &#039;url&#039; =&amp;gt; &#039;http://wiki.yobi.be/wiki/Mediawiki_RawFile&#039;,&lt;br /&gt;
                           &#039;description&#039; =&amp;gt; &#039;Downloads a RAW copy of &amp;lt;nowiki&amp;gt;&amp;lt;tag&amp;gt;data&amp;lt;/tag&amp;gt;&amp;lt;/nowiki&amp;gt; in a file&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;Useful e.g. to download a script or a patch&amp;lt;br&amp;gt;&#039;.&lt;br /&gt;
                                            &#039;It also allows what is called [http://en.wikipedia.org/wiki/Literate_programming Literate Programming]&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
And finally registration of the extension at the Mediawiki website according to the [http://www.mediawiki.org/wiki/Manual:Extensions Extensions Manual].&lt;br /&gt;
&lt;br /&gt;
So this extension has now [http://www.mediawiki.org/wiki/Extension:RawFile its own page on the official Mediawiki site].&lt;br /&gt;
&lt;br /&gt;
==Installation==&lt;br /&gt;
Download [{{#filelink: RawFile.php}} RawFile.php] and save it under the MediaWiki directory as extensions/RawFile/RawFile.php&lt;br /&gt;
&lt;br /&gt;
Add at the end of LocalSettings.php:&lt;br /&gt;
&amp;lt;source lang=php&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$IP/extensions/RawFile/RawFile.php&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
==Status==&lt;br /&gt;
If you use the extension properly the code is fully functional but it&#039;s rather raw on error handling.&lt;br /&gt;
==ChangeLog==&lt;br /&gt;
&#039;&#039;&#039;0.3&#039;&#039;&#039;&lt;br /&gt;
* Added optional parameter to &amp;lt;code&amp;gt;#fileLink&amp;lt;/code&amp;gt; to indicate that the file is on another local wiki page&lt;br /&gt;
&#039;&#039;&#039;0.2&#039;&#039;&#039;&lt;br /&gt;
* Fix problem with Content-Length mismatch when transport is gzipped (default for Mediawiki if client supports it)&lt;br /&gt;
&#039;&#039;&#039;0.1&#039;&#039;&#039;&lt;br /&gt;
* Initial version&lt;br /&gt;
==Known bugs==&lt;br /&gt;
Jani Uusitalo reported the following issue: &lt;br /&gt;
&amp;lt;br&amp;gt;For some reason, if you use Epiphany&#039;s &#039;Save as&#039; instead of a direct left-click, the downloaded file is a single byte. In Firefox the links work just fine, so this is probably an Epiphany bug. Uncommenting the &amp;lt;code&amp;gt;// wfResetOutputBuffers();&amp;lt;/code&amp;gt; line didn&#039;t help. If anyone knows a workaround to help Epiphany users without breaking the support of the other browsers, please speak up :-)&lt;br /&gt;
&lt;br /&gt;
==Questions and feedback==&lt;br /&gt;
If you&#039;ve any trouble, questions or suggestions, you can [[User:PhilippeTeuwen|contact me]].&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=MiscCrypto&amp;diff=5550</id>
		<title>MiscCrypto</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=MiscCrypto&amp;diff=5550"/>
		<updated>2009-03-10T08:34:11Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* To unlock password-protected pdfs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Under Windows==&lt;br /&gt;
===[http://www.cryptool.com/ CryptTool]===&lt;br /&gt;
* Demonstration and Reference Program for Cryptography + making AES executables&lt;br /&gt;
* freeware&lt;br /&gt;
===[http://axcrypt.sourceforge.net/ AxCrypt]===&lt;br /&gt;
* AES-128 File Encryption, Compression and double-click Edit/View for secure document storage on Windows 95/98/ME/NT/2K/XP, locally or remote.&lt;br /&gt;
* GPL&lt;br /&gt;
===[http://www.chilkatsoft.com/ChilkatSfx.asp Zip 2 Secure EXE]===&lt;br /&gt;
* AES-128/192/256 bits File Encryption, Create self-extracting EXE files from zip files&lt;br /&gt;
* freeware&lt;br /&gt;
==[[LoopCrypt]]==&lt;br /&gt;
==[[Encfs]]==&lt;br /&gt;
==[[TrueCrypt]]==&lt;br /&gt;
==[[LUKS]]==&lt;br /&gt;
&lt;br /&gt;
==Misc==&lt;br /&gt;
===To unlock password-protected pdfs===&lt;br /&gt;
* PDF documents may have up to 2 passwords:&lt;br /&gt;
** &#039;&#039;&#039;User password&#039;&#039;&#039;: protects read access to the document, and when no &#039;&#039;Owner password&#039;&#039; is specified, also protects permission settings.&lt;br /&gt;
** &#039;&#039;&#039;Owner password&#039;&#039;&#039;: protects full access to the document, and protects permission settings (printing, copying...)&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;pdftops&amp;lt;/tt&amp;gt; to convert a protected PDF to Postscript, and possibly combine it with &amp;lt;tt&amp;gt;ps2pdf&amp;lt;/tt&amp;gt; to obtain an unrestricted pdf. Knowing the &#039;&#039;Owner password&#039;&#039; is the easiest since that allows removing all restrictions. If not, it also works but in that case the permission &amp;lt;tt&amp;gt;allow Printing&amp;lt;/tt&amp;gt; must be set. If it is not the case, then &#039;&#039;Owner password&#039;&#039; is necessary. Also if &#039;&#039;User password&#039;&#039; is set (ie. pdf reader asks for a password at open), then it must be provided (providing &#039;&#039;Owner password&#039;&#039; is also ok of course).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get install gs-common xpdf-utils&lt;br /&gt;
# on Cygwin: install package xpdf&lt;br /&gt;
pdftops &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps                              # Owner pwd set but unknown and &#039;allow printing&#039; set&lt;br /&gt;
pdftops -upw &amp;lt;userpwd&amp;gt; &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps               # Same as above but user password also set&lt;br /&gt;
pdftops -opw &amp;lt;ownerpwd&amp;gt; &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps              # &#039;allow printing&#039; not set -&amp;gt; owner pwd is necessary&lt;br /&gt;
&lt;br /&gt;
pdftops -upw &amp;lt;password&amp;gt; &amp;lt;encrypted&amp;gt;.pdf -|ps2pdf - &amp;lt;decrypted&amp;gt;.pdf  # To generate a new PDF immediately&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An other solution is to use &#039;&#039;PDF Toolkit&#039;&#039; &amp;lt;tt&amp;gt;pdftk&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;apt-get install pdftk&amp;lt;/tt&amp;gt;). However unlike &#039;&#039;pdftops&#039;&#039; this method doesn&#039;t work when only &#039;&#039;user password&#039;&#039; is known but both passwords are set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;pdftk &amp;lt;encrypted&amp;gt;.pdf input_pw &amp;lt;password&amp;gt; output &amp;lt;decrypted&amp;gt;.pdf&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pdftk&amp;lt;/tt&amp;gt; can also be used to generate protected documents, and specifying permissions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pdftk &amp;lt;unprotected&amp;gt;.pdf output &amp;lt;protected&amp;gt;.pdf allow Printing owner_pw &amp;lt;ownerpwd&amp;gt; user_pw &amp;lt;userpwd&amp;gt;    #Allow HQ printing&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===pwsafe===&lt;br /&gt;
To use &#039;secure ram&#039; (thereby locking the data in memory and preventing it being flushed to disk) you may like to run it setuid root:&lt;br /&gt;
 $ sudo dpkg-statoverride --update --add --force root root 4755 /usr/bin/pwsafe&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=AndLinux&amp;diff=5372</id>
		<title>AndLinux</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=AndLinux&amp;diff=5372"/>
		<updated>2009-01-21T16:47:59Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Troubleshooting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Intro==&lt;br /&gt;
[http://www.andlinux.org/ andLinux] is a bundle of several pieces enabling a linux distribution to run with its kernel as a Windows service.&lt;br /&gt;
* [http://www.ubuntu.com/ Ubuntu]&lt;br /&gt;
* [http://www.colinux.org/ coLinux], a port of the Linux kernel to Windows&lt;br /&gt;
* [http://www.straightrunning.com/XmingNotes/ Xming], a X server for Windows&lt;br /&gt;
* [http://www.pulseaudio.org/ PulseAudio], the sound server&lt;br /&gt;
==Tips==&lt;br /&gt;
===Adding a shared drive===&lt;br /&gt;
Add sth like this to andLinux\settings.txt&lt;br /&gt;
 cofs1=D:\&lt;br /&gt;
And in the /etc/fstab of the Ubuntu:&lt;br /&gt;
 1 /mnt/d cofs defaults 0 0&lt;br /&gt;
===Running kgpg===&lt;br /&gt;
The problem is that once kgpg is iconified, I&#039;ve no idea where this icon goes and I cannot maximize the window anymore (it&#039;s also true for e.g. klipper)&lt;br /&gt;
&amp;lt;br&amp;gt;The trick is to use a dcop command to raise the window, you can play with kdcop to experiment&lt;br /&gt;
&amp;lt;br&amp;gt;So I added to andLinux\Launcher\menu.txt the following:&lt;br /&gt;
 Kgpg;kgpg.ico;pgrep kgpg &amp;gt; /dev/null || kgpg;dcop kgpg KeyInterface showKeyManager&lt;br /&gt;
The icon was converted from /usr/share/icons/hicolor/32x32/apps/kgpg.png with The Gimp&lt;br /&gt;
===Windows Explorer integration===&lt;br /&gt;
In the Windows Explorer there is now on right-click on a file a possibility to open it with Kate.&lt;br /&gt;
&amp;lt;br&amp;gt;And right-click on a folder allows it to be opened in Konqueror or Konsole.&lt;br /&gt;
&amp;lt;br&amp;gt;To do that it is creating the path file:///mnt/win/... so be sure that /mnt/win points to your data partition.&lt;br /&gt;
&lt;br /&gt;
If you want or need to hack into that part, have a look here:&lt;br /&gt;
* [http://www.andlinux.org/faq.php last point of the FAQ: Changing the Launcher Port]&lt;br /&gt;
* [http://andlinux.org/forum/viewtopic.php?p=939#939 a patched launcher.pl] to get it working with andCmd.exe too, as with [http://www.andlinux.org/forum/viewtopic.php?t=55  this example]&lt;br /&gt;
&lt;br /&gt;
And here is a patch by Thierry Walrant to allow more than one share and to fix the andCmd.exe bug as well, you can [{{#file:launcher.patch}} get the patch here]&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- launcher.pl	2008-07-03 05:26:40.000000000 -0400&lt;br /&gt;
+++ launcher.pl	2008-07-03 05:52:45.000000000 -0400&lt;br /&gt;
@@ -1,27 +1,44 @@&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 &lt;br /&gt;
 use IO::Socket;&lt;br /&gt;
+use strict;&lt;br /&gt;
 &lt;br /&gt;
+# Default settings.&lt;br /&gt;
+our $localPort = 81;&lt;br /&gt;
+our %pathPrefixes = (&lt;br /&gt;
+    &#039;/mnt/win/&#039;	=&amp;gt; &amp;quot;C:\\&amp;quot;&lt;br /&gt;
+    );&lt;br /&gt;
 &lt;br /&gt;
-$windowsPathPrefix = &amp;quot;C:\\&amp;quot;;&lt;br /&gt;
-$linuxPathPrefix = &amp;quot;/mnt/win/&amp;quot;;&lt;br /&gt;
+# Load config, if any.&lt;br /&gt;
+my $conf = &#039;/etc/launcher-conf.pl&#039;;&lt;br /&gt;
+require $conf if -f $conf;&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
-$sock = new IO::Socket::INET(LocalPort =&amp;gt; 81, Reuse =&amp;gt; 1, Listen =&amp;gt; 20) or die(&amp;quot;Error creating local socket: $@\n&amp;quot;);&lt;br /&gt;
+my $sock = new IO::Socket::INET(LocalPort =&amp;gt; $localPort, Reuse =&amp;gt; 1, Listen =&amp;gt; 20) or die(&amp;quot;Error creating local socket: $@\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
-while($client = $sock-&amp;gt;accept())&lt;br /&gt;
+while(my $client = $sock-&amp;gt;accept())&lt;br /&gt;
 {&lt;br /&gt;
-	$request = &amp;lt;$client&amp;gt;;&lt;br /&gt;
+	my $request = &amp;lt;$client&amp;gt;;&lt;br /&gt;
 	chomp $request;&lt;br /&gt;
 	if($request =~ m/^cmd=(.+)&amp;amp;file=(.*)$/)&lt;br /&gt;
 	{&lt;br /&gt;
-		$cmd = $1;&lt;br /&gt;
-		$file = $2;&lt;br /&gt;
+		my $cmd = $1;&lt;br /&gt;
+		my $file = $2;&lt;br /&gt;
 &lt;br /&gt;
-		$escapedWindowsPathPrefix = $windowsPathPrefix;&lt;br /&gt;
-		$escapedWindowsPathPrefix =~ s/\\/\\\\/g;&lt;br /&gt;
-		$file =~ s/$escapedWindowsPathPrefix/$linuxPathPrefix/g;&lt;br /&gt;
+		# Apply all mappings&lt;br /&gt;
+		foreach my $linuxPathPrefix ( keys %pathPrefixes ) {&lt;br /&gt;
+		    my $windowsPathPrefix = $pathPrefixes{$linuxPathPrefix};&lt;br /&gt;
+		    $windowsPathPrefix =~ s/\\/\\\\/g;&lt;br /&gt;
+		    $file =~ s/$windowsPathPrefix/$linuxPathPrefix/g;&lt;br /&gt;
+&lt;br /&gt;
+		    # Apply mapping to &#039;cmd&#039; as well (circumvent issue with&lt;br /&gt;
+		    # andCmd.exe which passes all arguments in &#039;cmd&#039;).&lt;br /&gt;
+		    $cmd =~ s/$windowsPathPrefix/$linuxPathPrefix/g;&lt;br /&gt;
+		}&lt;br /&gt;
+&lt;br /&gt;
+		# Finalize with back-slashes replacement.&lt;br /&gt;
 		$file =~ s/\\/\//g;&lt;br /&gt;
+		$cmd =~ s/\\/\//g;&lt;br /&gt;
 &lt;br /&gt;
 		system(&amp;quot;$cmd $file &amp;amp;&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
To use it you can use the hardcoded mapping as before or you can define your mappings in a config file /etc/launcher-conf.pl such as:&lt;br /&gt;
&amp;lt;source lang=perl&amp;gt;&lt;br /&gt;
# Configuration file for the launcher: /usr/local/sbin/launcher.pl&lt;br /&gt;
&lt;br /&gt;
%pathPrefixes = (&lt;br /&gt;
	&#039;/mnt/winC/&#039;	=&amp;gt; &#039;C:\\&#039;,&lt;br /&gt;
	&#039;/mnt/winD/&#039;	=&amp;gt; &#039;D:\\&#039;,&lt;br /&gt;
	&#039;/mnt/winZ/&#039;	=&amp;gt; &#039;Z:\\&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
# A Perl library MUST return 1&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please note this configuration assumes that the mount points /mnt/winC, /mnt/winD and /mnt/winZ are mounted on the root of the windows drives C:, D: and Z:. This allows you to launch KDE applications on any of your windows files and folders.&lt;br /&gt;
&lt;br /&gt;
===Starting Xming our own way===&lt;br /&gt;
By default Xming is started at boot time (cf folder Startup)&lt;br /&gt;
&amp;lt;br&amp;gt;If you don&#039;t want that and start Xming only when you need it, here is a replacement of andLinux/srvstart.bat&lt;br /&gt;
&amp;lt;source lang=dos&amp;gt;&lt;br /&gt;
@echo off&lt;br /&gt;
setlocal ENABLEEXTENSIONS&lt;br /&gt;
&lt;br /&gt;
rem Do we need to start xming?&lt;br /&gt;
set TASKNAME=xming.exe&lt;br /&gt;
tasklist /FI &amp;quot;IMAGENAME eq %TASKNAME%&amp;quot;  2&amp;gt; \nul | find /i &amp;quot;%TASKNAME%&amp;quot; &amp;gt; \nul&lt;br /&gt;
&lt;br /&gt;
IF ERRORLEVEL 1 CALL :STARTXMING&lt;br /&gt;
&lt;br /&gt;
net start andLinux&lt;br /&gt;
goto :EOF&lt;br /&gt;
&lt;br /&gt;
:STARTXMING&lt;br /&gt;
&lt;br /&gt;
echo Starting XMing...&lt;br /&gt;
start /D&amp;quot;C:\Program Files\andLinux&amp;quot; C:\Progra~1\andLinux\Xming\Xming.exe :0 -dpi 85 -ac -clipboard -notrayicon -c -multiwindow -reset -terminate -unixkill -logfile Xming.log&lt;br /&gt;
&lt;br /&gt;
goto :EOF&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
===Port forwarding===&lt;br /&gt;
To forward a port of the host to andLinux so it can run servers available to everybody: (instructions extracted from [http://colinux.wikia.com/wiki/Network#Forwarding_Ports_over_Slirp here])&lt;br /&gt;
&amp;lt;br&amp;gt;Edit your settings.txt and append some port forwarding infos to eth0:&lt;br /&gt;
 #eth0=slirp,&amp;lt;MAC&amp;gt;,tcp:&amp;lt;from Hosting OS port&amp;gt;:&amp;lt;to coLinux OS port&amp;gt;/...&lt;br /&gt;
 eth0=slirp,,tcp:22:22/tcp:80:80&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
===Startup delays===&lt;br /&gt;
* &#039;&#039;&#039;Interaction with Anti-Virus software&#039;&#039;&#039; - AV software may interact with the startup of AndLinux, typically by maintaining a lock on the 4GB disk image file &amp;lt;tt&amp;gt;base.drv&amp;lt;/tt&amp;gt; while it is scanned.&lt;br /&gt;
** &#039;&#039;&#039;Solution&#039;&#039;&#039;: To prevent this, one can exclude the andlinux directory from the AV on-access scanner. In McAfee, this is done by &#039;&#039;opening the &#039;&#039;&#039;VirusScan console&#039;&#039;&#039; &amp;amp;rarr; &#039;&#039;&#039;double-ckick&#039;&#039;&#039; On-Access Scanner &amp;amp;rarr; then select &#039;&#039;&#039;All Processes&#039;&#039;&#039; &amp;amp;rarr; open the pane &#039;&#039;&#039;Detection&#039;&#039;&#039; and click the button &#039;&#039;&#039;Exclusions...&#039;&#039;&#039; &amp;amp;rarr; click &#039;&#039;&#039;Add...&#039;&#039;&#039; to add a new exclusion &amp;amp;rarr; &#039;&#039;&#039;Browse&#039;&#039;&#039; to AndLinux directory and select &#039;&#039;&#039;Also exclude subfolders&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;Stalling when mounting /&#039;&#039;&#039; - You experience a huge delay during the startup process, and when launching the &#039;&#039;FLTK&#039;&#039; console, you observe that andlinux is stalling on the message below.&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding-left:2em;&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;ReiserFS: cobd0: warning: sh-2021: reiserfs_fill_super: can not find reiserfs on cobd0&lt;br /&gt;
kjournald starting.  Commit interval 5 seconds&lt;br /&gt;
EXT3-fs: mounted filesystem with ordered data mode.&lt;br /&gt;
Modules already installed.&lt;br /&gt;
Closing /&lt;br /&gt;
kjournald starting.  Commit interval 5 seconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
:* &#039;&#039;&#039;Solution&#039;&#039;&#039;: The fix proposed in [http://www.andlinux.org/forum/viewtopic.php?t=291&amp;amp;sid=7ef2f7b1234865dd3fabe645c1b48a25 this post] is to actually change the extension of the disk image file from &amp;lt;tt&amp;gt;.drv&amp;lt;/tt&amp;gt; to something like &amp;lt;tt&amp;gt;.drive&amp;lt;/tt&amp;gt; (ie. change &amp;lt;tt&amp;gt;./Drives/base.drv&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;./Drives/base.drive&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;./Drives/swap.drv&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;./Drives/swap.drive&amp;lt;/tt&amp;gt;) and adapt the configuration files &amp;lt;tt&amp;gt;./settings.txt&amp;lt;/tt&amp;gt; accordingly.&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=AndLinux&amp;diff=5371</id>
		<title>AndLinux</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=AndLinux&amp;diff=5371"/>
		<updated>2009-01-21T16:46:16Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Troubleshooting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Intro==&lt;br /&gt;
[http://www.andlinux.org/ andLinux] is a bundle of several pieces enabling a linux distribution to run with its kernel as a Windows service.&lt;br /&gt;
* [http://www.ubuntu.com/ Ubuntu]&lt;br /&gt;
* [http://www.colinux.org/ coLinux], a port of the Linux kernel to Windows&lt;br /&gt;
* [http://www.straightrunning.com/XmingNotes/ Xming], a X server for Windows&lt;br /&gt;
* [http://www.pulseaudio.org/ PulseAudio], the sound server&lt;br /&gt;
==Tips==&lt;br /&gt;
===Adding a shared drive===&lt;br /&gt;
Add sth like this to andLinux\settings.txt&lt;br /&gt;
 cofs1=D:\&lt;br /&gt;
And in the /etc/fstab of the Ubuntu:&lt;br /&gt;
 1 /mnt/d cofs defaults 0 0&lt;br /&gt;
===Running kgpg===&lt;br /&gt;
The problem is that once kgpg is iconified, I&#039;ve no idea where this icon goes and I cannot maximize the window anymore (it&#039;s also true for e.g. klipper)&lt;br /&gt;
&amp;lt;br&amp;gt;The trick is to use a dcop command to raise the window, you can play with kdcop to experiment&lt;br /&gt;
&amp;lt;br&amp;gt;So I added to andLinux\Launcher\menu.txt the following:&lt;br /&gt;
 Kgpg;kgpg.ico;pgrep kgpg &amp;gt; /dev/null || kgpg;dcop kgpg KeyInterface showKeyManager&lt;br /&gt;
The icon was converted from /usr/share/icons/hicolor/32x32/apps/kgpg.png with The Gimp&lt;br /&gt;
===Windows Explorer integration===&lt;br /&gt;
In the Windows Explorer there is now on right-click on a file a possibility to open it with Kate.&lt;br /&gt;
&amp;lt;br&amp;gt;And right-click on a folder allows it to be opened in Konqueror or Konsole.&lt;br /&gt;
&amp;lt;br&amp;gt;To do that it is creating the path file:///mnt/win/... so be sure that /mnt/win points to your data partition.&lt;br /&gt;
&lt;br /&gt;
If you want or need to hack into that part, have a look here:&lt;br /&gt;
* [http://www.andlinux.org/faq.php last point of the FAQ: Changing the Launcher Port]&lt;br /&gt;
* [http://andlinux.org/forum/viewtopic.php?p=939#939 a patched launcher.pl] to get it working with andCmd.exe too, as with [http://www.andlinux.org/forum/viewtopic.php?t=55  this example]&lt;br /&gt;
&lt;br /&gt;
And here is a patch by Thierry Walrant to allow more than one share and to fix the andCmd.exe bug as well, you can [{{#file:launcher.patch}} get the patch here]&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- launcher.pl	2008-07-03 05:26:40.000000000 -0400&lt;br /&gt;
+++ launcher.pl	2008-07-03 05:52:45.000000000 -0400&lt;br /&gt;
@@ -1,27 +1,44 @@&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 &lt;br /&gt;
 use IO::Socket;&lt;br /&gt;
+use strict;&lt;br /&gt;
 &lt;br /&gt;
+# Default settings.&lt;br /&gt;
+our $localPort = 81;&lt;br /&gt;
+our %pathPrefixes = (&lt;br /&gt;
+    &#039;/mnt/win/&#039;	=&amp;gt; &amp;quot;C:\\&amp;quot;&lt;br /&gt;
+    );&lt;br /&gt;
 &lt;br /&gt;
-$windowsPathPrefix = &amp;quot;C:\\&amp;quot;;&lt;br /&gt;
-$linuxPathPrefix = &amp;quot;/mnt/win/&amp;quot;;&lt;br /&gt;
+# Load config, if any.&lt;br /&gt;
+my $conf = &#039;/etc/launcher-conf.pl&#039;;&lt;br /&gt;
+require $conf if -f $conf;&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
-$sock = new IO::Socket::INET(LocalPort =&amp;gt; 81, Reuse =&amp;gt; 1, Listen =&amp;gt; 20) or die(&amp;quot;Error creating local socket: $@\n&amp;quot;);&lt;br /&gt;
+my $sock = new IO::Socket::INET(LocalPort =&amp;gt; $localPort, Reuse =&amp;gt; 1, Listen =&amp;gt; 20) or die(&amp;quot;Error creating local socket: $@\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
-while($client = $sock-&amp;gt;accept())&lt;br /&gt;
+while(my $client = $sock-&amp;gt;accept())&lt;br /&gt;
 {&lt;br /&gt;
-	$request = &amp;lt;$client&amp;gt;;&lt;br /&gt;
+	my $request = &amp;lt;$client&amp;gt;;&lt;br /&gt;
 	chomp $request;&lt;br /&gt;
 	if($request =~ m/^cmd=(.+)&amp;amp;file=(.*)$/)&lt;br /&gt;
 	{&lt;br /&gt;
-		$cmd = $1;&lt;br /&gt;
-		$file = $2;&lt;br /&gt;
+		my $cmd = $1;&lt;br /&gt;
+		my $file = $2;&lt;br /&gt;
 &lt;br /&gt;
-		$escapedWindowsPathPrefix = $windowsPathPrefix;&lt;br /&gt;
-		$escapedWindowsPathPrefix =~ s/\\/\\\\/g;&lt;br /&gt;
-		$file =~ s/$escapedWindowsPathPrefix/$linuxPathPrefix/g;&lt;br /&gt;
+		# Apply all mappings&lt;br /&gt;
+		foreach my $linuxPathPrefix ( keys %pathPrefixes ) {&lt;br /&gt;
+		    my $windowsPathPrefix = $pathPrefixes{$linuxPathPrefix};&lt;br /&gt;
+		    $windowsPathPrefix =~ s/\\/\\\\/g;&lt;br /&gt;
+		    $file =~ s/$windowsPathPrefix/$linuxPathPrefix/g;&lt;br /&gt;
+&lt;br /&gt;
+		    # Apply mapping to &#039;cmd&#039; as well (circumvent issue with&lt;br /&gt;
+		    # andCmd.exe which passes all arguments in &#039;cmd&#039;).&lt;br /&gt;
+		    $cmd =~ s/$windowsPathPrefix/$linuxPathPrefix/g;&lt;br /&gt;
+		}&lt;br /&gt;
+&lt;br /&gt;
+		# Finalize with back-slashes replacement.&lt;br /&gt;
 		$file =~ s/\\/\//g;&lt;br /&gt;
+		$cmd =~ s/\\/\//g;&lt;br /&gt;
 &lt;br /&gt;
 		system(&amp;quot;$cmd $file &amp;amp;&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
To use it you can use the hardcoded mapping as before or you can define your mappings in a config file /etc/launcher-conf.pl such as:&lt;br /&gt;
&amp;lt;source lang=perl&amp;gt;&lt;br /&gt;
# Configuration file for the launcher: /usr/local/sbin/launcher.pl&lt;br /&gt;
&lt;br /&gt;
%pathPrefixes = (&lt;br /&gt;
	&#039;/mnt/winC/&#039;	=&amp;gt; &#039;C:\\&#039;,&lt;br /&gt;
	&#039;/mnt/winD/&#039;	=&amp;gt; &#039;D:\\&#039;,&lt;br /&gt;
	&#039;/mnt/winZ/&#039;	=&amp;gt; &#039;Z:\\&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
# A Perl library MUST return 1&lt;br /&gt;
1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please note this configuration assumes that the mount points /mnt/winC, /mnt/winD and /mnt/winZ are mounted on the root of the windows drives C:, D: and Z:. This allows you to launch KDE applications on any of your windows files and folders.&lt;br /&gt;
&lt;br /&gt;
===Starting Xming our own way===&lt;br /&gt;
By default Xming is started at boot time (cf folder Startup)&lt;br /&gt;
&amp;lt;br&amp;gt;If you don&#039;t want that and start Xming only when you need it, here is a replacement of andLinux/srvstart.bat&lt;br /&gt;
&amp;lt;source lang=dos&amp;gt;&lt;br /&gt;
@echo off&lt;br /&gt;
setlocal ENABLEEXTENSIONS&lt;br /&gt;
&lt;br /&gt;
rem Do we need to start xming?&lt;br /&gt;
set TASKNAME=xming.exe&lt;br /&gt;
tasklist /FI &amp;quot;IMAGENAME eq %TASKNAME%&amp;quot;  2&amp;gt; \nul | find /i &amp;quot;%TASKNAME%&amp;quot; &amp;gt; \nul&lt;br /&gt;
&lt;br /&gt;
IF ERRORLEVEL 1 CALL :STARTXMING&lt;br /&gt;
&lt;br /&gt;
net start andLinux&lt;br /&gt;
goto :EOF&lt;br /&gt;
&lt;br /&gt;
:STARTXMING&lt;br /&gt;
&lt;br /&gt;
echo Starting XMing...&lt;br /&gt;
start /D&amp;quot;C:\Program Files\andLinux&amp;quot; C:\Progra~1\andLinux\Xming\Xming.exe :0 -dpi 85 -ac -clipboard -notrayicon -c -multiwindow -reset -terminate -unixkill -logfile Xming.log&lt;br /&gt;
&lt;br /&gt;
goto :EOF&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
===Port forwarding===&lt;br /&gt;
To forward a port of the host to andLinux so it can run servers available to everybody: (instructions extracted from [http://colinux.wikia.com/wiki/Network#Forwarding_Ports_over_Slirp here])&lt;br /&gt;
&amp;lt;br&amp;gt;Edit your settings.txt and append some port forwarding infos to eth0:&lt;br /&gt;
 #eth0=slirp,&amp;lt;MAC&amp;gt;,tcp:&amp;lt;from Hosting OS port&amp;gt;:&amp;lt;to coLinux OS port&amp;gt;/...&lt;br /&gt;
 eth0=slirp,,tcp:22:22/tcp:80:80&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
===Startup delays===&lt;br /&gt;
* &#039;&#039;&#039;Interaction with Anti-Virus software&#039;&#039;&#039; - AV software may interact with the startup of AndLinux, typically by maintaining a lock on the 4GB disk image file &amp;lt;tt&amp;gt;base.drv&amp;lt;/tt&amp;gt; while it is scanned.&lt;br /&gt;
** &#039;&#039;&#039;Solution&#039;&#039;&#039;: To prevent this, one can exclude the andlinux directory from the AV on-access scanner. In McAfee, this is done by &#039;&#039;opening the &#039;&#039;&#039;VirusScan console&#039;&#039;&#039; &amp;amp;rarr; &#039;&#039;&#039;double-ckick&#039;&#039;&#039; On-Access Scanner &amp;amp;rarr; then select &#039;&#039;&#039;All Processes&#039;&#039;&#039; &amp;amp;rarr; open the pane &#039;&#039;&#039;Detection&#039;&#039;&#039; and click the button &#039;&#039;&#039;Exclusions...&#039;&#039;&#039; &amp;amp;rarr; click &#039;&#039;&#039;Add...&#039;&#039;&#039; to add a new exclusion &amp;amp;rarr; &#039;&#039;&#039;Browse&#039;&#039;&#039; to AndLinux directory and select &#039;&#039;&#039;Also exclude subfolders&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;Stalling when mounting /&#039;&#039;&#039; - You experience a huge delay during the startup process, and when launching the &#039;&#039;FLTK&#039;&#039; console, you observe that andlinux is stalling on the message below.&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding-left:2em;&amp;quot;&amp;gt;&amp;lt;pre&amp;gt;ReiserFS: codb0: warning sh-2021: reiserfs_fill_super: can not find reiserfs on codb0\nkjournald starting. Commit 5 seconds&amp;lt;/pre&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
:* &#039;&#039;&#039;Solution&#039;&#039;&#039;: The fix proposed in [http://www.andlinux.org/forum/viewtopic.php?t=291&amp;amp;sid=7ef2f7b1234865dd3fabe645c1b48a25 this post] is to actually change the extension of the disk image file from &amp;lt;tt&amp;gt;.drv&amp;lt;/tt&amp;gt; to something like &amp;lt;tt&amp;gt;.drive&amp;lt;/tt&amp;gt; (ie. change &amp;lt;tt&amp;gt;./Drives/base.drv&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;./Drives/base.drive&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;./Drives/swap.drv&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;./Drives/swap.drive&amp;lt;/tt&amp;gt;) and adapt the configuration files &amp;lt;tt&amp;gt;./settings.txt&amp;lt;/tt&amp;gt; accordingly.&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Cygwin-multitee&amp;diff=5316</id>
		<title>Cygwin-multitee</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Cygwin-multitee&amp;diff=5316"/>
		<updated>2008-11-25T02:33:18Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* The patch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;multitee&#039;&#039;&#039; sends multiple inputs to multiple outputs. Check this [http://code.dogmap.org/fdtools/multitee/ page].&lt;br /&gt;
Original is [http://cr.yp.to/software/multitee-3.0.shar.gz here], or can also be found here on [http://ftp.de.debian.org/debian/pool/main/m/multitee/multitee_3.0.orig.tar.gz Debian].&lt;br /&gt;
&lt;br /&gt;
Below you&#039;ll find a patch to build &#039;&#039;multitee&#039;&#039; on cygwin (and possibly any other POSIX distribution). To build, just untar the &#039;&#039;multitee&#039;&#039; archive, and then in a shell:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt;../multitee-3.0-cygwin.patch&lt;br /&gt;
$ make&lt;br /&gt;
$ cp multitee.1 /usr/local/man/man1&lt;br /&gt;
$ cp multitee.exe /usr/local/bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ multitee 0-1,4,5 4&amp;gt; foo 5&amp;gt; bar             # same as tee foo bar with better blocking behavior&lt;br /&gt;
$ multitee 0:1 3:1 4:1,2 6:7                 # various merge and copy&lt;br /&gt;
$ tcpclient server smtp multitee 0:7 6:1e0   # e0 tell multitee to quit as soon connection close&lt;br /&gt;
$ multitee 0:3 3:1                           # same as &#039;socat - FD:3&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The patch ==&lt;br /&gt;
The patch ports calls to BSD &#039;&#039;signal.h&#039;&#039; API (&amp;lt;tt&amp;gt;struct sigvec&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigvec()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigmask()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigblock()&amp;lt;/tt&amp;gt;...) to the POSIX API (&amp;lt;tt&amp;gt;struct sigaction&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigaction()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigprocmask()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigfillset()&amp;lt;/tt&amp;gt;...). Here the [{{#file: multitee-3.0-cygwin.patch}} patch]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- multitee-3.0/Makefile	1970-01-01 01:00:00.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/Makefile	2008-11-24 03:35:43.875000000 +0100&lt;br /&gt;
@@ -0,0 +1,9 @@&lt;br /&gt;
+&lt;br /&gt;
+all:		multitee tee&lt;br /&gt;
+&lt;br /&gt;
+multitee:       multitee.o sigdfl.o sigsched.o ralloc.o getopt.o fmt.o scan.o&lt;br /&gt;
+tee:            tee.o getopt.o ralloc.o fmt.o&lt;br /&gt;
+&lt;br /&gt;
+clean:&lt;br /&gt;
+	rm -f tee multitee *.o *.a *.0 *~ core&lt;br /&gt;
+&lt;br /&gt;
--- multitee-3.0/multitee.c	1998-02-17 03:25:43.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/multitee.c	2008-11-24 03:38:51.296875000 +0100&lt;br /&gt;
@@ -180,7 +180,7 @@&lt;br /&gt;
  int in;&lt;br /&gt;
  int w;&lt;br /&gt;
 &lt;br /&gt;
- ioscp = (ioscstack) p;&lt;br /&gt;
+ ioscp = (struct iosc *) p;&lt;br /&gt;
  in = ioscp-&amp;gt;in;&lt;br /&gt;
 &lt;br /&gt;
  if (ioscp-&amp;gt;dead)&lt;br /&gt;
--- multitee-3.0/ralloc.c	1998-02-17 03:25:43.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/ralloc.c	2008-11-24 03:41:24.093750000 +0100&lt;br /&gt;
@@ -40,7 +40,7 @@&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;ralloc.h&amp;quot;&lt;br /&gt;
 #include &amp;quot;sod.h&amp;quot;&lt;br /&gt;
-extern char *malloc(); /*XXXX*/&lt;br /&gt;
+extern void *malloc(); /*XXXX*/&lt;br /&gt;
 extern void free();&lt;br /&gt;
 &lt;br /&gt;
 typedef int (*foo)();&lt;br /&gt;
--- multitee-3.0/sigdfl.c	1998-02-17 03:25:44.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/sigdfl.c	2008-11-24 03:39:57.734375000 +0100&lt;br /&gt;
@@ -2,6 +2,7 @@&lt;br /&gt;
 Daniel J. Bernstein, brnstnd@nyu.edu.&lt;br /&gt;
 No dependencies.&lt;br /&gt;
 Requires BSD signal syscalls.&lt;br /&gt;
+24/11/08: Michael Peeters - Ported to POSIX signal.h (tested under Cygwin)&lt;br /&gt;
 7/18/91: Baseline. sigdfl 1.0, public domain.&lt;br /&gt;
 No known patent problems.&lt;br /&gt;
 &lt;br /&gt;
@@ -18,18 +19,20 @@&lt;br /&gt;
 &lt;br /&gt;
 static int cont = 0;&lt;br /&gt;
 &lt;br /&gt;
-static sigcont() /* XXX: should declare with right signal type */&lt;br /&gt;
+static void sigcont(int sig) /* XXX: should declare with right signal type */&lt;br /&gt;
 {&lt;br /&gt;
+ (void)sig;&lt;br /&gt;
  cont = 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int sigdfl(sig)&lt;br /&gt;
 int sig;&lt;br /&gt;
 {&lt;br /&gt;
- int oldmask;&lt;br /&gt;
- struct sigvec oldvec;&lt;br /&gt;
- struct sigvec vec;&lt;br /&gt;
- struct sigvec contvec;&lt;br /&gt;
+ sigset_t oldmask;&lt;br /&gt;
+ sigset_t workmask;&lt;br /&gt;
+ struct sigaction oldvec;&lt;br /&gt;
+ struct sigaction vec;&lt;br /&gt;
+ struct sigaction contvec;&lt;br /&gt;
 &lt;br /&gt;
  if (sig == SIGCONT)&lt;br /&gt;
    return 0; /* strategy below simply cannot work for CONT */&lt;br /&gt;
@@ -43,19 +46,20 @@&lt;br /&gt;
  /* killing the process and without stopping the process so that it&#039;ll */&lt;br /&gt;
  /* receive CONT later, then we will enter an infinite loop. [sigh] */&lt;br /&gt;
  /* XXX: put maximum time wastage on this? */&lt;br /&gt;
- oldmask = sigblock(0);&lt;br /&gt;
- sigblock(~0);&lt;br /&gt;
+ sigprocmask(SIG_BLOCK,NULL,&amp;amp;oldmask);&lt;br /&gt;
+ sigfillset(&amp;amp;workmask);&lt;br /&gt;
+ sigprocmask(SIG_BLOCK,&amp;amp;workmask,NULL);&lt;br /&gt;
  /* now we won&#039;t receive any signals */&lt;br /&gt;
- vec.sv_handler = SIG_DFL;&lt;br /&gt;
- vec.sv_mask = ~0;&lt;br /&gt;
- vec.sv_flags = 0;&lt;br /&gt;
- if (sigvec(sig,&amp;amp;vec,&amp;amp;oldvec) == -1)&lt;br /&gt;
+ vec.sa_handler = SIG_DFL;&lt;br /&gt;
+ vec.sa_mask = ~0;&lt;br /&gt;
+ vec.sa_flags = 0;&lt;br /&gt;
+ if (sigaction(sig,&amp;amp;vec,&amp;amp;oldvec) == -1)&lt;br /&gt;
    if ((sig != SIGSTOP) &amp;amp;&amp;amp; (sig != SIGKILL))&lt;br /&gt;
      return -1;&lt;br /&gt;
- vec.sv_handler = sigcont;&lt;br /&gt;
- vec.sv_mask = ~0;&lt;br /&gt;
- vec.sv_flags = 0;&lt;br /&gt;
- if (sigvec(SIGCONT,&amp;amp;vec,&amp;amp;contvec) == -1)&lt;br /&gt;
+ vec.sa_handler = sigcont;&lt;br /&gt;
+ vec.sa_mask = ~0;&lt;br /&gt;
+ vec.sa_flags = 0;&lt;br /&gt;
+ if (sigaction(SIGCONT,&amp;amp;vec,&amp;amp;contvec) == -1)&lt;br /&gt;
    return -1;&lt;br /&gt;
  cont = 0;&lt;br /&gt;
  if (kill(getpid(),sig) == -1)&lt;br /&gt;
@@ -66,16 +70,20 @@&lt;br /&gt;
     reached this point, sigcont() might already have been run. that&#039;s&lt;br /&gt;
     why cont must be set to 0 before the kill(). */&lt;br /&gt;
  /* after this next bit we may receive sig and/or CONT */&lt;br /&gt;
- sigsetmask(~(sigmask(sig) | sigmask(SIGCONT)));&lt;br /&gt;
+ sigfillset(&amp;amp;workmask);&lt;br /&gt;
+ sigdelset(&amp;amp;workmask,sig);&lt;br /&gt;
+ sigdelset(&amp;amp;workmask,SIGCONT);&lt;br /&gt;
+ sigprocmask(SIG_SETMASK,&amp;amp;workmask,NULL);&lt;br /&gt;
  /* in the near future, sig will in fact be received */&lt;br /&gt;
  while (!cont) /* dead loop until we receive CONT */&lt;br /&gt;
    ; /* XXX: there should be a syscall so we don&#039;t have to loop here */&lt;br /&gt;
- sigblock(~0);&lt;br /&gt;
+ sigfillset(&amp;amp;workmask);&lt;br /&gt;
+ sigprocmask(SIG_BLOCK,&amp;amp;workmask,NULL);&lt;br /&gt;
  /* now we won&#039;t receive any signals */&lt;br /&gt;
- (void) sigvec(sig,&amp;amp;oldvec,&amp;amp;vec); /* we don&#039;t care if it fails */&lt;br /&gt;
- (void) sigvec(SIGCONT,&amp;amp;contvec,&amp;amp;vec);&lt;br /&gt;
+ (void) sigaction(sig,&amp;amp;oldvec,&amp;amp;vec); /* we don&#039;t care if it fails */&lt;br /&gt;
+ (void) sigaction(SIGCONT,&amp;amp;contvec,&amp;amp;vec);&lt;br /&gt;
  /* now signal handlers are back to normal */&lt;br /&gt;
- (void) sigsetmask(oldmask);&lt;br /&gt;
+ (void) sigprocmask(SIG_SETMASK,&amp;amp;oldmask,NULL);&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
--- multitee-3.0/sigsched.c	1998-02-17 03:25:44.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/sigsched.c	2008-11-24 03:35:43.906250000 +0100&lt;br /&gt;
@@ -2,6 +2,7 @@&lt;br /&gt;
 Daniel J. Bernstein, brnstnd@nyu.edu.&lt;br /&gt;
 Depends on ralloc.h, sod.h, config/fdsettrouble.h.&lt;br /&gt;
 Requires BSDish environment: reliable signals, sig{vec,block,setmask}, select.&lt;br /&gt;
+24/11/08: Michael Peeters - Ported to POSIX signal.h (tested under Cygwin)&lt;br /&gt;
 9/1/91: Added worst-case fdset, FD_ZERO, etc. definitions.&lt;br /&gt;
 8/25/91: sigsched 1.1, public domain.&lt;br /&gt;
 8/25/91: Fixed bug that sigs[sched-&amp;gt;blah].r didn&#039;t force instant timeout.&lt;br /&gt;
@@ -31,17 +32,6 @@&lt;br /&gt;
 &lt;br /&gt;
 /* XXX: should restore signal set exactly after ss_exec returns */&lt;br /&gt;
 &lt;br /&gt;
-typedef int sigc_set; /*XXX */&lt;br /&gt;
-&lt;br /&gt;
-#define sigc_ismember(x,i) (*(x) &amp;amp; (1 &amp;lt;&amp;lt; ((i) - 1)))&lt;br /&gt;
-#define sigc_addset(x,i) (*(x) |= (1 &amp;lt;&amp;lt; ((i) - 1)))&lt;br /&gt;
-#define sigc_emptyset(x) (*(x) = 0)&lt;br /&gt;
-&lt;br /&gt;
-/*       sigprocmask(SIG_UNBLOCK,xxxx,(sigc_set *) 0); */&lt;br /&gt;
-#define sigc_unblock(x) (sigsetmask(sigblock(0) &amp;amp; ~*(x)))&lt;br /&gt;
-/*       sigprocmask(SIG_BLOCK,xxxx,(sigc_set *) 0); */&lt;br /&gt;
-#define sigc_block(x) (sigblock(*(x)))&lt;br /&gt;
-&lt;br /&gt;
 #ifndef NSIG&lt;br /&gt;
 #define NSIG 64 /* it&#039;s not as if any sane system has more than 32 */&lt;br /&gt;
 #endif&lt;br /&gt;
@@ -333,8 +323,8 @@&lt;br /&gt;
  sigs[i].r = 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
-static sigc_set sigstorage;&lt;br /&gt;
-static sigc_set *xxxx = 0;&lt;br /&gt;
+static sigset_t sigstorage;&lt;br /&gt;
+static sigset_t *xxxx = 0;&lt;br /&gt;
 &lt;br /&gt;
 int ss_addsig(i)&lt;br /&gt;
 int i;&lt;br /&gt;
@@ -344,9 +334,9 @@&lt;br /&gt;
  if (!xxxx)&lt;br /&gt;
   {&lt;br /&gt;
    xxxx = &amp;amp;sigstorage;&lt;br /&gt;
-   sigc_emptyset(xxxx);&lt;br /&gt;
+   sigemptyset(xxxx);&lt;br /&gt;
   }&lt;br /&gt;
- sigc_addset(xxxx,i);&lt;br /&gt;
+ sigaddset(xxxx,i);&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
@@ -362,7 +352,7 @@&lt;br /&gt;
 int ss_exec()&lt;br /&gt;
 {&lt;br /&gt;
  int i;&lt;br /&gt;
- struct sigvec sv;&lt;br /&gt;
+ struct sigaction sv;&lt;br /&gt;
  recvlist recvhead;&lt;br /&gt;
  recvlist temp;&lt;br /&gt;
  schedlist sch;&lt;br /&gt;
@@ -371,18 +361,18 @@&lt;br /&gt;
 &lt;br /&gt;
  if (xxxx)&lt;br /&gt;
   {&lt;br /&gt;
-   sigc_block(xxxx);&lt;br /&gt;
+   sigprocmask(SIG_BLOCK,xxxx,NULL);&lt;br /&gt;
 &lt;br /&gt;
-   sv.sv_handler = handle;&lt;br /&gt;
-   sv.sv_mask = *xxxx; /* so handle won&#039;t interrupt itself */&lt;br /&gt;
-   sv.sv_flags = 0;&lt;br /&gt;
+   sv.sa_handler = handle;&lt;br /&gt;
+   sv.sa_mask = *xxxx; /* so handle won&#039;t interrupt itself */&lt;br /&gt;
+   sv.sa_flags = 0;&lt;br /&gt;
 &lt;br /&gt;
    /* XXX: Does anyone but me find it absolutely idiotic that POSIX&lt;br /&gt;
       doesn&#039;t provide a way to get each member of a signal set in turn? */&lt;br /&gt;
    for (i = 0;i &amp;lt; NUMSIGS;i++)&lt;br /&gt;
     {&lt;br /&gt;
-     if (sigc_ismember(xxxx,i))&lt;br /&gt;
-       if (sigvec(i,&amp;amp;sv,(struct sigvec *) 0) == -1) /*XXX: really trash orig? */&lt;br /&gt;
+     if (sigismember(xxxx,i))&lt;br /&gt;
+       if (sigaction(i,&amp;amp;sv,(struct sigaction *) 0) == -1) /*XXX: really trash orig? */&lt;br /&gt;
 	 ; /* not our problem */&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
@@ -498,7 +488,7 @@&lt;br /&gt;
       }&lt;br /&gt;
 &lt;br /&gt;
      if (xxxx)&lt;br /&gt;
-       sigc_unblock(xxxx);&lt;br /&gt;
+       sigprocmask(SIG_UNBLOCK,xxxx,NULL);&lt;br /&gt;
      /* This is the only section where handle() can be called. */&lt;br /&gt;
      /* XXX: If maxfd == -1, this select functions as a pause. */&lt;br /&gt;
      /* XXX: If maxfd == -1 and timeout is instant, should skip select. */&lt;br /&gt;
@@ -510,7 +500,7 @@&lt;br /&gt;
      r = select(maxfd + 1,&amp;amp;rfds,&amp;amp;wfds,&amp;amp;efds,&amp;amp;timeout);&lt;br /&gt;
        /* XXX: does this necessarily prevent timeout race conditions? */&lt;br /&gt;
      if (xxxx)&lt;br /&gt;
-       sigc_block(xxxx);&lt;br /&gt;
+       sigprocmask(SIG_BLOCK,xxxx,NULL);&lt;br /&gt;
 &lt;br /&gt;
      if (r == -1)&lt;br /&gt;
       {&lt;br /&gt;
@@ -529,7 +519,7 @@&lt;br /&gt;
 &lt;br /&gt;
      for (sp = schedhead;sp;sp = SODnext(sp))&lt;br /&gt;
       {&lt;br /&gt;
-       switch(SODdata(sp).sig-&amp;gt;type) &lt;br /&gt;
+       switch(SODdata(sp).sig-&amp;gt;type)&lt;br /&gt;
 	{&lt;br /&gt;
 	 case JUNK:&lt;br /&gt;
 	   break;&lt;br /&gt;
@@ -595,7 +585,7 @@&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
  if (xxxx)&lt;br /&gt;
-   sigc_unblock(xxxx);&lt;br /&gt;
+   sigprocmask(SIG_UNBLOCK,xxxx,NULL);&lt;br /&gt;
    /* XXX: should put this at other returns as well */&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Cygwin-multitee&amp;diff=5315</id>
		<title>Cygwin-multitee</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Cygwin-multitee&amp;diff=5315"/>
		<updated>2008-11-25T02:30:11Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: New page: &amp;#039;&amp;#039;&amp;#039;multitee&amp;#039;&amp;#039;&amp;#039; sends multiple inputs to multiple outputs. Check this [http://code.dogmap.org/fdtools/multitee/ page]. Original is [http://cr.yp.to/software/multitee-3.0.shar.gz here], or c...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;multitee&#039;&#039;&#039; sends multiple inputs to multiple outputs. Check this [http://code.dogmap.org/fdtools/multitee/ page].&lt;br /&gt;
Original is [http://cr.yp.to/software/multitee-3.0.shar.gz here], or can also be found here on [http://ftp.de.debian.org/debian/pool/main/m/multitee/multitee_3.0.orig.tar.gz Debian].&lt;br /&gt;
&lt;br /&gt;
Below you&#039;ll find a patch to build &#039;&#039;multitee&#039;&#039; on cygwin (and possibly any other POSIX distribution). To build, just untar the &#039;&#039;multitee&#039;&#039; archive, and then in a shell:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt;../multitee-3.0-cygwin.patch&lt;br /&gt;
$ make&lt;br /&gt;
$ cp multitee.1 /usr/local/man/man1&lt;br /&gt;
$ cp multitee.exe /usr/local/bin&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ multitee 0-1,4,5 4&amp;gt; foo 5&amp;gt; bar             # same as tee foo bar with better blocking behavior&lt;br /&gt;
$ multitee 0:1 3:1 4:1,2 6:7                 # various merge and copy&lt;br /&gt;
$ tcpclient server smtp multitee 0:7 6:1e0   # e0 tell multitee to quit as soon connection close&lt;br /&gt;
$ multitee 0:3 3:1                           # same as &#039;socat - FD:3&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The patch ==&lt;br /&gt;
Here the [{{#file: multitee-3.0-cygwin.patch}} patch] to build &#039;&#039;multitee&#039;&#039; on &#039;&#039;Cygwin&#039;&#039;. The patch ports calls to BSD &#039;&#039;signal.h&#039;&#039; API (&amp;lt;tt&amp;gt;struct sigvec&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigvec()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigmask()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigblock()&amp;lt;/tt&amp;gt;...) to the POSIX API (&amp;lt;tt&amp;gt;struct sigaction&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigaction()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigprocmask()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;sigfillset()&amp;lt;/tt&amp;gt;...).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- multitee-3.0/Makefile	1970-01-01 01:00:00.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/Makefile	2008-11-24 03:35:43.875000000 +0100&lt;br /&gt;
@@ -0,0 +1,9 @@&lt;br /&gt;
+&lt;br /&gt;
+all:		multitee tee&lt;br /&gt;
+&lt;br /&gt;
+multitee:       multitee.o sigdfl.o sigsched.o ralloc.o getopt.o fmt.o scan.o&lt;br /&gt;
+tee:            tee.o getopt.o ralloc.o fmt.o&lt;br /&gt;
+&lt;br /&gt;
+clean:&lt;br /&gt;
+	rm -f tee multitee *.o *.a *.0 *~ core&lt;br /&gt;
+&lt;br /&gt;
--- multitee-3.0/multitee.c	1998-02-17 03:25:43.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/multitee.c	2008-11-24 03:38:51.296875000 +0100&lt;br /&gt;
@@ -180,7 +180,7 @@&lt;br /&gt;
  int in;&lt;br /&gt;
  int w;&lt;br /&gt;
 &lt;br /&gt;
- ioscp = (ioscstack) p;&lt;br /&gt;
+ ioscp = (struct iosc *) p;&lt;br /&gt;
  in = ioscp-&amp;gt;in;&lt;br /&gt;
 &lt;br /&gt;
  if (ioscp-&amp;gt;dead)&lt;br /&gt;
--- multitee-3.0/ralloc.c	1998-02-17 03:25:43.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/ralloc.c	2008-11-24 03:41:24.093750000 +0100&lt;br /&gt;
@@ -40,7 +40,7 @@&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;ralloc.h&amp;quot;&lt;br /&gt;
 #include &amp;quot;sod.h&amp;quot;&lt;br /&gt;
-extern char *malloc(); /*XXXX*/&lt;br /&gt;
+extern void *malloc(); /*XXXX*/&lt;br /&gt;
 extern void free();&lt;br /&gt;
 &lt;br /&gt;
 typedef int (*foo)();&lt;br /&gt;
--- multitee-3.0/sigdfl.c	1998-02-17 03:25:44.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/sigdfl.c	2008-11-24 03:39:57.734375000 +0100&lt;br /&gt;
@@ -2,6 +2,7 @@&lt;br /&gt;
 Daniel J. Bernstein, brnstnd@nyu.edu.&lt;br /&gt;
 No dependencies.&lt;br /&gt;
 Requires BSD signal syscalls.&lt;br /&gt;
+24/11/08: Michael Peeters - Ported to POSIX signal.h (tested under Cygwin)&lt;br /&gt;
 7/18/91: Baseline. sigdfl 1.0, public domain.&lt;br /&gt;
 No known patent problems.&lt;br /&gt;
 &lt;br /&gt;
@@ -18,18 +19,20 @@&lt;br /&gt;
 &lt;br /&gt;
 static int cont = 0;&lt;br /&gt;
 &lt;br /&gt;
-static sigcont() /* XXX: should declare with right signal type */&lt;br /&gt;
+static void sigcont(int sig) /* XXX: should declare with right signal type */&lt;br /&gt;
 {&lt;br /&gt;
+ (void)sig;&lt;br /&gt;
  cont = 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int sigdfl(sig)&lt;br /&gt;
 int sig;&lt;br /&gt;
 {&lt;br /&gt;
- int oldmask;&lt;br /&gt;
- struct sigvec oldvec;&lt;br /&gt;
- struct sigvec vec;&lt;br /&gt;
- struct sigvec contvec;&lt;br /&gt;
+ sigset_t oldmask;&lt;br /&gt;
+ sigset_t workmask;&lt;br /&gt;
+ struct sigaction oldvec;&lt;br /&gt;
+ struct sigaction vec;&lt;br /&gt;
+ struct sigaction contvec;&lt;br /&gt;
 &lt;br /&gt;
  if (sig == SIGCONT)&lt;br /&gt;
    return 0; /* strategy below simply cannot work for CONT */&lt;br /&gt;
@@ -43,19 +46,20 @@&lt;br /&gt;
  /* killing the process and without stopping the process so that it&#039;ll */&lt;br /&gt;
  /* receive CONT later, then we will enter an infinite loop. [sigh] */&lt;br /&gt;
  /* XXX: put maximum time wastage on this? */&lt;br /&gt;
- oldmask = sigblock(0);&lt;br /&gt;
- sigblock(~0);&lt;br /&gt;
+ sigprocmask(SIG_BLOCK,NULL,&amp;amp;oldmask);&lt;br /&gt;
+ sigfillset(&amp;amp;workmask);&lt;br /&gt;
+ sigprocmask(SIG_BLOCK,&amp;amp;workmask,NULL);&lt;br /&gt;
  /* now we won&#039;t receive any signals */&lt;br /&gt;
- vec.sv_handler = SIG_DFL;&lt;br /&gt;
- vec.sv_mask = ~0;&lt;br /&gt;
- vec.sv_flags = 0;&lt;br /&gt;
- if (sigvec(sig,&amp;amp;vec,&amp;amp;oldvec) == -1)&lt;br /&gt;
+ vec.sa_handler = SIG_DFL;&lt;br /&gt;
+ vec.sa_mask = ~0;&lt;br /&gt;
+ vec.sa_flags = 0;&lt;br /&gt;
+ if (sigaction(sig,&amp;amp;vec,&amp;amp;oldvec) == -1)&lt;br /&gt;
    if ((sig != SIGSTOP) &amp;amp;&amp;amp; (sig != SIGKILL))&lt;br /&gt;
      return -1;&lt;br /&gt;
- vec.sv_handler = sigcont;&lt;br /&gt;
- vec.sv_mask = ~0;&lt;br /&gt;
- vec.sv_flags = 0;&lt;br /&gt;
- if (sigvec(SIGCONT,&amp;amp;vec,&amp;amp;contvec) == -1)&lt;br /&gt;
+ vec.sa_handler = sigcont;&lt;br /&gt;
+ vec.sa_mask = ~0;&lt;br /&gt;
+ vec.sa_flags = 0;&lt;br /&gt;
+ if (sigaction(SIGCONT,&amp;amp;vec,&amp;amp;contvec) == -1)&lt;br /&gt;
    return -1;&lt;br /&gt;
  cont = 0;&lt;br /&gt;
  if (kill(getpid(),sig) == -1)&lt;br /&gt;
@@ -66,16 +70,20 @@&lt;br /&gt;
     reached this point, sigcont() might already have been run. that&#039;s&lt;br /&gt;
     why cont must be set to 0 before the kill(). */&lt;br /&gt;
  /* after this next bit we may receive sig and/or CONT */&lt;br /&gt;
- sigsetmask(~(sigmask(sig) | sigmask(SIGCONT)));&lt;br /&gt;
+ sigfillset(&amp;amp;workmask);&lt;br /&gt;
+ sigdelset(&amp;amp;workmask,sig);&lt;br /&gt;
+ sigdelset(&amp;amp;workmask,SIGCONT);&lt;br /&gt;
+ sigprocmask(SIG_SETMASK,&amp;amp;workmask,NULL);&lt;br /&gt;
  /* in the near future, sig will in fact be received */&lt;br /&gt;
  while (!cont) /* dead loop until we receive CONT */&lt;br /&gt;
    ; /* XXX: there should be a syscall so we don&#039;t have to loop here */&lt;br /&gt;
- sigblock(~0);&lt;br /&gt;
+ sigfillset(&amp;amp;workmask);&lt;br /&gt;
+ sigprocmask(SIG_BLOCK,&amp;amp;workmask,NULL);&lt;br /&gt;
  /* now we won&#039;t receive any signals */&lt;br /&gt;
- (void) sigvec(sig,&amp;amp;oldvec,&amp;amp;vec); /* we don&#039;t care if it fails */&lt;br /&gt;
- (void) sigvec(SIGCONT,&amp;amp;contvec,&amp;amp;vec);&lt;br /&gt;
+ (void) sigaction(sig,&amp;amp;oldvec,&amp;amp;vec); /* we don&#039;t care if it fails */&lt;br /&gt;
+ (void) sigaction(SIGCONT,&amp;amp;contvec,&amp;amp;vec);&lt;br /&gt;
  /* now signal handlers are back to normal */&lt;br /&gt;
- (void) sigsetmask(oldmask);&lt;br /&gt;
+ (void) sigprocmask(SIG_SETMASK,&amp;amp;oldmask,NULL);&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
--- multitee-3.0/sigsched.c	1998-02-17 03:25:44.000000000 +0100&lt;br /&gt;
+++ multitee-3.0-cygwin/sigsched.c	2008-11-24 03:35:43.906250000 +0100&lt;br /&gt;
@@ -2,6 +2,7 @@&lt;br /&gt;
 Daniel J. Bernstein, brnstnd@nyu.edu.&lt;br /&gt;
 Depends on ralloc.h, sod.h, config/fdsettrouble.h.&lt;br /&gt;
 Requires BSDish environment: reliable signals, sig{vec,block,setmask}, select.&lt;br /&gt;
+24/11/08: Michael Peeters - Ported to POSIX signal.h (tested under Cygwin)&lt;br /&gt;
 9/1/91: Added worst-case fdset, FD_ZERO, etc. definitions.&lt;br /&gt;
 8/25/91: sigsched 1.1, public domain.&lt;br /&gt;
 8/25/91: Fixed bug that sigs[sched-&amp;gt;blah].r didn&#039;t force instant timeout.&lt;br /&gt;
@@ -31,17 +32,6 @@&lt;br /&gt;
 &lt;br /&gt;
 /* XXX: should restore signal set exactly after ss_exec returns */&lt;br /&gt;
 &lt;br /&gt;
-typedef int sigc_set; /*XXX */&lt;br /&gt;
-&lt;br /&gt;
-#define sigc_ismember(x,i) (*(x) &amp;amp; (1 &amp;lt;&amp;lt; ((i) - 1)))&lt;br /&gt;
-#define sigc_addset(x,i) (*(x) |= (1 &amp;lt;&amp;lt; ((i) - 1)))&lt;br /&gt;
-#define sigc_emptyset(x) (*(x) = 0)&lt;br /&gt;
-&lt;br /&gt;
-/*       sigprocmask(SIG_UNBLOCK,xxxx,(sigc_set *) 0); */&lt;br /&gt;
-#define sigc_unblock(x) (sigsetmask(sigblock(0) &amp;amp; ~*(x)))&lt;br /&gt;
-/*       sigprocmask(SIG_BLOCK,xxxx,(sigc_set *) 0); */&lt;br /&gt;
-#define sigc_block(x) (sigblock(*(x)))&lt;br /&gt;
-&lt;br /&gt;
 #ifndef NSIG&lt;br /&gt;
 #define NSIG 64 /* it&#039;s not as if any sane system has more than 32 */&lt;br /&gt;
 #endif&lt;br /&gt;
@@ -333,8 +323,8 @@&lt;br /&gt;
  sigs[i].r = 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
-static sigc_set sigstorage;&lt;br /&gt;
-static sigc_set *xxxx = 0;&lt;br /&gt;
+static sigset_t sigstorage;&lt;br /&gt;
+static sigset_t *xxxx = 0;&lt;br /&gt;
 &lt;br /&gt;
 int ss_addsig(i)&lt;br /&gt;
 int i;&lt;br /&gt;
@@ -344,9 +334,9 @@&lt;br /&gt;
  if (!xxxx)&lt;br /&gt;
   {&lt;br /&gt;
    xxxx = &amp;amp;sigstorage;&lt;br /&gt;
-   sigc_emptyset(xxxx);&lt;br /&gt;
+   sigemptyset(xxxx);&lt;br /&gt;
   }&lt;br /&gt;
- sigc_addset(xxxx,i);&lt;br /&gt;
+ sigaddset(xxxx,i);&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
@@ -362,7 +352,7 @@&lt;br /&gt;
 int ss_exec()&lt;br /&gt;
 {&lt;br /&gt;
  int i;&lt;br /&gt;
- struct sigvec sv;&lt;br /&gt;
+ struct sigaction sv;&lt;br /&gt;
  recvlist recvhead;&lt;br /&gt;
  recvlist temp;&lt;br /&gt;
  schedlist sch;&lt;br /&gt;
@@ -371,18 +361,18 @@&lt;br /&gt;
 &lt;br /&gt;
  if (xxxx)&lt;br /&gt;
   {&lt;br /&gt;
-   sigc_block(xxxx);&lt;br /&gt;
+   sigprocmask(SIG_BLOCK,xxxx,NULL);&lt;br /&gt;
 &lt;br /&gt;
-   sv.sv_handler = handle;&lt;br /&gt;
-   sv.sv_mask = *xxxx; /* so handle won&#039;t interrupt itself */&lt;br /&gt;
-   sv.sv_flags = 0;&lt;br /&gt;
+   sv.sa_handler = handle;&lt;br /&gt;
+   sv.sa_mask = *xxxx; /* so handle won&#039;t interrupt itself */&lt;br /&gt;
+   sv.sa_flags = 0;&lt;br /&gt;
 &lt;br /&gt;
    /* XXX: Does anyone but me find it absolutely idiotic that POSIX&lt;br /&gt;
       doesn&#039;t provide a way to get each member of a signal set in turn? */&lt;br /&gt;
    for (i = 0;i &amp;lt; NUMSIGS;i++)&lt;br /&gt;
     {&lt;br /&gt;
-     if (sigc_ismember(xxxx,i))&lt;br /&gt;
-       if (sigvec(i,&amp;amp;sv,(struct sigvec *) 0) == -1) /*XXX: really trash orig? */&lt;br /&gt;
+     if (sigismember(xxxx,i))&lt;br /&gt;
+       if (sigaction(i,&amp;amp;sv,(struct sigaction *) 0) == -1) /*XXX: really trash orig? */&lt;br /&gt;
 	 ; /* not our problem */&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
@@ -498,7 +488,7 @@&lt;br /&gt;
       }&lt;br /&gt;
 &lt;br /&gt;
      if (xxxx)&lt;br /&gt;
-       sigc_unblock(xxxx);&lt;br /&gt;
+       sigprocmask(SIG_UNBLOCK,xxxx,NULL);&lt;br /&gt;
      /* This is the only section where handle() can be called. */&lt;br /&gt;
      /* XXX: If maxfd == -1, this select functions as a pause. */&lt;br /&gt;
      /* XXX: If maxfd == -1 and timeout is instant, should skip select. */&lt;br /&gt;
@@ -510,7 +500,7 @@&lt;br /&gt;
      r = select(maxfd + 1,&amp;amp;rfds,&amp;amp;wfds,&amp;amp;efds,&amp;amp;timeout);&lt;br /&gt;
        /* XXX: does this necessarily prevent timeout race conditions? */&lt;br /&gt;
      if (xxxx)&lt;br /&gt;
-       sigc_block(xxxx);&lt;br /&gt;
+       sigprocmask(SIG_BLOCK,xxxx,NULL);&lt;br /&gt;
 &lt;br /&gt;
      if (r == -1)&lt;br /&gt;
       {&lt;br /&gt;
@@ -529,7 +519,7 @@&lt;br /&gt;
 &lt;br /&gt;
      for (sp = schedhead;sp;sp = SODnext(sp))&lt;br /&gt;
       {&lt;br /&gt;
-       switch(SODdata(sp).sig-&amp;gt;type) &lt;br /&gt;
+       switch(SODdata(sp).sig-&amp;gt;type)&lt;br /&gt;
 	{&lt;br /&gt;
 	 case JUNK:&lt;br /&gt;
 	   break;&lt;br /&gt;
@@ -595,7 +585,7 @@&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
  if (xxxx)&lt;br /&gt;
-   sigc_unblock(xxxx);&lt;br /&gt;
+   sigprocmask(SIG_UNBLOCK,xxxx,NULL);&lt;br /&gt;
    /* XXX: should put this at other returns as well */&lt;br /&gt;
  return 0;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5302</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5302"/>
		<updated>2008-11-07T15:14:09Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Master was not happy... Let&amp;#039;s roll back first to previous version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Pre-requisite=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* patch, tar, make, gcc&lt;br /&gt;
* crypt&lt;br /&gt;
* libgdbm-devel&lt;br /&gt;
* libtool&lt;br /&gt;
* inetutils&lt;br /&gt;
* cygrunsrv&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of Courier Authentication Library using the module userdb to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
==Compilation and installation==&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
Solution source: http://lists.cairographics.org/archives/cairo/2004-April/001125.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;userdb&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
 --without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
 --with-mailgroup=mkgroup-l-d&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready execute the following command.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Take again a long pause... then check the result and install the libraries&lt;br /&gt;
&lt;br /&gt;
 $ make check&lt;br /&gt;
 $ make install&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Running==&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
==Testing authlib==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
==Courier Authentication Config==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Courier-IMAP=&lt;br /&gt;
==Compilation and installation==&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&lt;br /&gt;
Take a walk... and when ready execute the following command to build the package.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Time to go for some coffee... and then install the package with the usual&lt;br /&gt;
&lt;br /&gt;
 $ make install&lt;br /&gt;
 $ make install-configure&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==Running==&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==All in one==&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin service==&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
=Maildir=&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
=Mairix - index and search mail folders=&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
=Offlineimap=&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5301</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5301"/>
		<updated>2008-11-07T10:40:45Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Installing as a Windows Service */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-imap-4.4.1.tar.bz2&lt;br /&gt;
$ cd courier-imap-4.4.1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a walk or some coffee... and when ready build the package and install it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make install&lt;br /&gt;
$ make install-configure&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
== Configuration Files and Scripts ==&lt;br /&gt;
&lt;br /&gt;
If not present yet, add &amp;lt;tt&amp;gt;/usr/local/bin&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;/usr/local/sbin&amp;lt;/tt&amp;gt; to your path (ideally in &amp;lt;tt&amp;gt;/etc/bash.bashrc&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
PATH=/usr/local/bin:/usr/local/sbin:$PATH&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create configuration file for &#039;&#039;&#039;authdaemond&#039;&#039;&#039; (&amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
And edit its content to change number of daemons (I use three):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the file &amp;lt;tt&amp;gt;/usr/lib/courier-imap/etc/imapd&amp;lt;/tt&amp;gt;, taking care to adapt &#039;&#039;&#039;IMAP_ULIMITD&#039;&#039;&#039; accordingly:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ADDRESS=127.0.0.1                    #Typ. use 0 or 127.0.0.1&lt;br /&gt;
...&lt;br /&gt;
IMAP_ULIMITD=2097152                 #Set same value as returned by &#039;ulimit -v&#039; or imapd.rc will complain&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create link to authlib and imap daemon in &amp;lt;tt&amp;gt;/etc/rc.d/init.d&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ln -s /usr/local/sbin/authdaemond /etc/rc.d/init.d/courier-authdaemon&lt;br /&gt;
ln -s /usr/lib/courier-imap/libexec/imapd.rc /etc/rc.d/init.d/courier-imap&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== IMAP Accounts ==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. &amp;lt;tt&amp;gt;[http://linux.die.net/man/8/makeuserdb man makeuserdb]&amp;lt;/tt&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
First create user mailbox (replace &#039;&#039;username&#039;&#039; with user account name) with &amp;lt;tt&amp;gt;maildirmake&amp;lt;/tt&amp;gt;. Repeat for all users:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /home/username                          #if don&#039;t exist yet...&lt;br /&gt;
cd /home/username&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake ~username/MailDir/$i; done&lt;br /&gt;
# Create also default Maildir for new users&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake /etc/skel/MailDir/$i; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next create the user authentication database &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch /usr/local/etc/authlib/userdb&lt;br /&gt;
chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
#Repeat for each username:&lt;br /&gt;
pw2userdb | grep &amp;quot;^username&amp;quot;&amp;gt;&amp;gt;/usr/local/etc/authlib/userdb   # Fill userdb from /etc/passwd user entry&lt;br /&gt;
userdb username set mail=~username/MailDir                    # Specify user MailDir location&lt;br /&gt;
userdbpw | userdb username set systempw                       # Set user account password&lt;br /&gt;
...&lt;br /&gt;
makeuserdb                                                    # Create binary database&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Start the daemons with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/etc/rc.d/init.d/courier-authdaemon start&lt;br /&gt;
/etc/rc.d/init.d/courier-imap start&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stop the daemons with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/etc/rc.d/init.d/courier-imap stop&lt;br /&gt;
/etc/rc.d/init.d/courier-authdaemon stop&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
If not done yet, install and configure &#039;&#039;&#039;syslogd&#039;&#039;&#039;. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program and install &#039;&#039;&#039;inetutils&#039;&#039;&#039; package (contains &#039;&#039;&#039;syslogd&#039;&#039;&#039;). Configure &#039;&#039;&#039;syslogd&#039;&#039;&#039; with the following command, which will create the file &amp;lt;tt&amp;gt;/etc/syslogd.conf&amp;lt;/tt&amp;gt; file and install a windows service using &#039;&#039;&#039;cygrunsrv&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ syslogd-config                   #if not configured yet&lt;br /&gt;
$ net start syslogd                #if not started yet&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit &#039;&#039;&#039;authdaemond&#039;&#039;&#039; configuration file &amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt; to enable full debug messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and restart &#039;&#039;&#039;courier-authdaemon&#039;&#039;&#039; to take changes into effect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ /etc/rc.d/init.d/courier-authdaemon stop&lt;br /&gt;
$ /etc/rc.d/init.d/courier-authdaemon start&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Testing &#039;&#039;Courier Authentication Library&#039;&#039; with &#039;&#039;&#039;authtest&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ export PATH=$PATH:/usr/local/lib/bin               #because authtest needs a .DLL library there (found with strace)&lt;br /&gt;
$ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This should produce something similar to the transcript below (where &amp;lt;tt&amp;gt;CCCCCC&amp;lt;/tt&amp;gt; is your cleartext password, and &amp;lt;tt&amp;gt;XXXXXX&amp;lt;/tt&amp;gt; is your encrypted password as provided in &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check that everything is fine in &amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt; (see [http://www.courier-mta.org/authlib/README.authdebug.html] for details):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cat /var/log/messages&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Testing &#039;&#039;&#039;Courier-IMAP&#039;&#039;&#039; through &#039;&#039;&#039;telnet&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ telnet localhost 143&lt;br /&gt;
&amp;lt;/source&lt;br /&gt;
&lt;br /&gt;
In the &#039;&#039;telnet&#039;&#039; session, type the following test scripts (replace &#039;&#039;username&#039;&#039; and &#039;&#039;password&#039;&#039; accordingly):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
001 LOGIN username password&lt;br /&gt;
002 EXAMINE INBOX&lt;br /&gt;
003 LOGOUT&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Server must reply with &#039;&#039;&#039;OK&#039;&#039;&#039; messages along with some more information (see also [http://www.courier-mta.org/authlib/README.authdebug.html] for details).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
When testing is done, don&#039;t forget to reset debugging in &amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;&#039;strace&#039;&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ strace /usr/local/sbin/authtest             # This will open a dialog box to complain about DLL.&lt;br /&gt;
$ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
$ /usr/local/sbin/authtest ausername&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can install &#039;&#039;Courier&#039;&#039; as a Windows Service. Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /etc/rc.d/init.d/courier-authdaemon&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/etc/rc.d/init.d/courier-authdaemon stop&amp;quot;&lt;br /&gt;
	echo &amp;quot;STOPPING: /etc/rc.d/init.d/courier-imap&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/etc/rc.d/init.d/courier-imap stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /etc/rc.d/init.d/courier-authdaemon as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/etc/rc.d/init.d/courier-authdaemon start&amp;quot;&lt;br /&gt;
echo &amp;quot;STARTING: /etc/rc.d/init.d/courier-imap as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/etc/rc.d/init.d/courier-imap start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change &#039;&#039;username&#039;&#039; and save it to your favorite location, say &amp;lt;tt&amp;gt;/usr/local/sbin&amp;lt;/tt&amp;gt;. The service script must be executable by &#039;&#039;SYSTEM&#039;&#039;, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
  --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cygrunsrv --start imapd&lt;br /&gt;
# or&lt;br /&gt;
$ net start imapd&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ps -a&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5300</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5300"/>
		<updated>2008-11-07T10:32:09Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-imap-4.4.1.tar.bz2&lt;br /&gt;
$ cd courier-imap-4.4.1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a walk or some coffee... and when ready build the package and install it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make install&lt;br /&gt;
$ make install-configure&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
== Configuration Files and Scripts ==&lt;br /&gt;
&lt;br /&gt;
If not present yet, add &amp;lt;tt&amp;gt;/usr/local/bin&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;/usr/local/sbin&amp;lt;/tt&amp;gt; to your path (ideally in &amp;lt;tt&amp;gt;/etc/bash.bashrc&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
PATH=/usr/local/bin:/usr/local/sbin:$PATH&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create configuration file for &#039;&#039;&#039;authdaemond&#039;&#039;&#039; (&amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
And edit its content to change number of daemons (I use three):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the file &amp;lt;tt&amp;gt;/usr/lib/courier-imap/etc/imapd&amp;lt;/tt&amp;gt;, taking care to adapt &#039;&#039;&#039;IMAP_ULIMITD&#039;&#039;&#039; accordingly:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ADDRESS=127.0.0.1                    #Typ. use 0 or 127.0.0.1&lt;br /&gt;
...&lt;br /&gt;
IMAP_ULIMITD=2097152                 #Set same value as returned by &#039;ulimit -v&#039; or imapd.rc will complain&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create link to authlib and imap daemon in &amp;lt;tt&amp;gt;/etc/rc.d/init.d&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ln -s /usr/local/sbin/authdaemond /etc/rc.d/init.d/courier-authdaemon&lt;br /&gt;
ln -s /usr/lib/courier-imap/libexec/imapd.rc /etc/rc.d/init.d/courier-imap&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== IMAP Accounts ==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. &amp;lt;tt&amp;gt;[http://linux.die.net/man/8/makeuserdb man makeuserdb]&amp;lt;/tt&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
First create user mailbox (replace &#039;&#039;username&#039;&#039; with user account name) with &amp;lt;tt&amp;gt;maildirmake&amp;lt;/tt&amp;gt;. Repeat for all users:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /home/username                          #if don&#039;t exist yet...&lt;br /&gt;
cd /home/username&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake ~username/MailDir/$i; done&lt;br /&gt;
# Create also default Maildir for new users&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake /etc/skel/MailDir/$i; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next create the user authentication database &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch /usr/local/etc/authlib/userdb&lt;br /&gt;
chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
#Repeat for each username:&lt;br /&gt;
pw2userdb | grep &amp;quot;^username&amp;quot;&amp;gt;&amp;gt;/usr/local/etc/authlib/userdb   # Fill userdb from /etc/passwd user entry&lt;br /&gt;
userdb username set mail=~username/MailDir                    # Specify user MailDir location&lt;br /&gt;
userdbpw | userdb username set systempw                       # Set user account password&lt;br /&gt;
...&lt;br /&gt;
makeuserdb                                                    # Create binary database&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Start the daemons with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/etc/rc.d/init.d/courier-authdaemon start&lt;br /&gt;
/etc/rc.d/init.d/courier-imap start&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stop the daemons with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/etc/rc.d/init.d/courier-imap stop&lt;br /&gt;
/etc/rc.d/init.d/courier-authdaemon stop&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
If not done yet, install and configure &#039;&#039;&#039;syslogd&#039;&#039;&#039;. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program and install &#039;&#039;&#039;inetutils&#039;&#039;&#039; package (contains &#039;&#039;&#039;syslogd&#039;&#039;&#039;). Configure &#039;&#039;&#039;syslogd&#039;&#039;&#039; with the following command, which will create the file &amp;lt;tt&amp;gt;/etc/syslogd.conf&amp;lt;/tt&amp;gt; file and install a windows service using &#039;&#039;&#039;cygrunsrv&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ syslogd-config                   #if not configured yet&lt;br /&gt;
$ net start syslogd                #if not started yet&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit &#039;&#039;&#039;authdaemond&#039;&#039;&#039; configuration file &amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt; to enable full debug messages:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and restart &#039;&#039;&#039;courier-authdaemon&#039;&#039;&#039; to take changes into effect:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ /etc/rc.d/init.d/courier-authdaemon stop&lt;br /&gt;
$ /etc/rc.d/init.d/courier-authdaemon start&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Testing &#039;&#039;Courier Authentication Library&#039;&#039; with &#039;&#039;&#039;authtest&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ export PATH=$PATH:/usr/local/lib/bin               #because authtest needs a .DLL library there (found with strace)&lt;br /&gt;
$ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This should produce something similar to the transcript below (where &amp;lt;tt&amp;gt;CCCCCC&amp;lt;/tt&amp;gt; is your cleartext password, and &amp;lt;tt&amp;gt;XXXXXX&amp;lt;/tt&amp;gt; is your encrypted password as provided in &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check that everything is fine in &amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt; (see [http://www.courier-mta.org/authlib/README.authdebug.html] for details):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cat /var/log/messages&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Testing &#039;&#039;&#039;Courier-IMAP&#039;&#039;&#039; through &#039;&#039;&#039;telnet&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ telnet localhost 143&lt;br /&gt;
&amp;lt;/source&lt;br /&gt;
&lt;br /&gt;
In the &#039;&#039;telnet&#039;&#039; session, type the following test scripts (replace &#039;&#039;username&#039;&#039; and &#039;&#039;password&#039;&#039; accordingly):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
001 LOGIN username password&lt;br /&gt;
002 EXAMINE INBOX&lt;br /&gt;
003 LOGOUT&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Server must reply with &#039;&#039;&#039;OK&#039;&#039;&#039; messages along with some more information (see also [http://www.courier-mta.org/authlib/README.authdebug.html] for details).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
When testing is done, don&#039;t forget to reset debugging in &amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;&#039;strace&#039;&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ strace /usr/local/sbin/authtest             # This will open a dialog box to complain about DLL.&lt;br /&gt;
$ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
$ /usr/local/sbin/authtest ausername&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5299</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5299"/>
		<updated>2008-11-07T10:07:05Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Running */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-imap-4.4.1.tar.bz2&lt;br /&gt;
$ cd courier-imap-4.4.1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a walk or some coffee... and when ready build the package and install it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make install&lt;br /&gt;
$ make install-configure&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
== Configuration Files and Scripts ==&lt;br /&gt;
&lt;br /&gt;
If not present yet, add &amp;lt;tt&amp;gt;/usr/local/bin&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;/usr/local/sbin&amp;lt;/tt&amp;gt; to your path (ideally in &amp;lt;tt&amp;gt;/etc/bash.bashrc&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
PATH=/usr/local/bin:/usr/local/sbin:$PATH&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create configuration file for &#039;&#039;&#039;authdaemond&#039;&#039;&#039; (&amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
And edit its content to change number of daemons (I use three):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the file &amp;lt;tt&amp;gt;/usr/lib/courier-imap/etc/imapd&amp;lt;/tt&amp;gt;, taking care to adapt &#039;&#039;&#039;IMAP_ULIMITD&#039;&#039;&#039; accordingly:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ADDRESS=127.0.0.1                    #Typ. use 0 or 127.0.0.1&lt;br /&gt;
...&lt;br /&gt;
IMAP_ULIMITD=2097152                 #Set same value as returned by &#039;ulimit -v&#039; or imapd.rc will complain&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create link to authlib and imap daemon in &amp;lt;tt&amp;gt;/etc/rc.d/init.d&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ln -s /usr/local/sbin/authdaemond /etc/rc.d/init.d/courier-authdaemon&lt;br /&gt;
ln -s /usr/lib/courier-imap/libexec/imapd.rc /etc/rc.d/init.d/courier-imap&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== IMAP Accounts ==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. &amp;lt;tt&amp;gt;[http://linux.die.net/man/8/makeuserdb man makeuserdb]&amp;lt;/tt&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
First create user mailbox (replace &#039;&#039;username&#039;&#039; with user account name) with &amp;lt;tt&amp;gt;maildirmake&amp;lt;/tt&amp;gt;. Repeat for all users:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /home/username                          #if don&#039;t exist yet...&lt;br /&gt;
cd /home/username&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake ~username/MailDir/$i; done&lt;br /&gt;
# Create also default Maildir for new users&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake /etc/skel/MailDir/$i; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next create the user authentication database &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch /usr/local/etc/authlib/userdb&lt;br /&gt;
chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
#Repeat for each username:&lt;br /&gt;
pw2userdb | grep &amp;quot;^username&amp;quot;&amp;gt;&amp;gt;/usr/local/etc/authlib/userdb   # Fill userdb from /etc/passwd user entry&lt;br /&gt;
userdb username set mail=~username/MailDir                    # Specify user MailDir location&lt;br /&gt;
userdbpw | userdb username set systempw                       # Set user account password&lt;br /&gt;
...&lt;br /&gt;
makeuserdb                                                    # Create binary database&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Start the daemons with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/etc/rc.d/init.d/courier-authdaemon start&lt;br /&gt;
/etc/rc.d/init.d/courier-imap start&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Stop the daemons with the following commands:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/etc/rc.d/init.d/courier-imap stop&lt;br /&gt;
/etc/rc.d/init.d/courier-authdaemon stop&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5298</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5298"/>
		<updated>2008-11-07T10:03:39Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Configuring Courier */ Too much subtitles... why not a subtitle for each sentence ;-)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-imap-4.4.1.tar.bz2&lt;br /&gt;
$ cd courier-imap-4.4.1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a walk or some coffee... and when ready build the package and install it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make install&lt;br /&gt;
$ make install-configure&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
== Configuration Files and Scripts ==&lt;br /&gt;
&lt;br /&gt;
If not present yet, add &amp;lt;tt&amp;gt;/usr/local/bin&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;/usr/local/sbin&amp;lt;/tt&amp;gt; to your path (ideally in &amp;lt;tt&amp;gt;/etc/bash.bashrc&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
PATH=/usr/local/bin:/usr/local/sbin:$PATH&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create configuration file for &#039;&#039;&#039;authdaemond&#039;&#039;&#039; (&amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
And edit its content to change number of daemons (I use three):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit the file &amp;lt;tt&amp;gt;/usr/lib/courier-imap/etc/imapd&amp;lt;/tt&amp;gt;, taking care to adapt &#039;&#039;&#039;IMAP_ULIMITD&#039;&#039;&#039; accordingly:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ADDRESS=127.0.0.1                    #Typ. use 0 or 127.0.0.1&lt;br /&gt;
...&lt;br /&gt;
IMAP_ULIMITD=2097152                 #Set same value as returned by &#039;ulimit -v&#039; or imapd.rc will complain&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create link to authlib and imap daemon in &amp;lt;tt&amp;gt;/etc/rc.d/init.d&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ln -s /usr/local/sbin/authdaemond /etc/rc.d/init.d/courier-authdaemon&lt;br /&gt;
ln -s /usr/lib/courier-imap/libexec/imapd.rc /etc/rc.d/init.d/courier-imap&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== IMAP Accounts ==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. &amp;lt;tt&amp;gt;[http://linux.die.net/man/8/makeuserdb man makeuserdb]&amp;lt;/tt&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
First create user mailbox (replace &#039;&#039;username&#039;&#039; with user account name) with &amp;lt;tt&amp;gt;maildirmake&amp;lt;/tt&amp;gt;. Repeat for all users:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /home/username                          #if don&#039;t exist yet...&lt;br /&gt;
cd /home/username&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake ~username/MailDir/$i; done&lt;br /&gt;
# Create also default Maildir for new users&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake /etc/skel/MailDir/$i; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next create the user authentication database &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch /usr/local/etc/authlib/userdb&lt;br /&gt;
chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
#Repeat for each username:&lt;br /&gt;
pw2userdb | grep &amp;quot;^username&amp;quot;&amp;gt;&amp;gt;/usr/local/etc/authlib/userdb   # Fill userdb from /etc/passwd user entry&lt;br /&gt;
userdb username set mail=~username/MailDir                    # Specify user MailDir location&lt;br /&gt;
userdbpw | userdb username set systempw                       # Set user account password&lt;br /&gt;
...&lt;br /&gt;
makeuserdb                                                    # Create binary database&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5297</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5297"/>
		<updated>2008-11-07T09:58:08Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Configuring Courier */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-imap-4.4.1.tar.bz2&lt;br /&gt;
$ cd courier-imap-4.4.1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a walk or some coffee... and when ready build the package and install it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make install&lt;br /&gt;
$ make install-configure&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
If not present yet, add &amp;lt;tt&amp;gt;/usr/local/bin&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;/usr/local/sbin&amp;lt;/tt&amp;gt; to your path (ideally in &amp;lt;tt&amp;gt;/etc/bash.bashrc&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
PATH=/usr/local/bin:/usr/local/sbin:$PATH&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==courier-authlib==&lt;br /&gt;
&lt;br /&gt;
Create configuration file for &#039;&#039;&#039;authdaemond&#039;&#039;&#039; (&amp;lt;tt&amp;gt;/usr/local/etc/authlib/authdaemonrc&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
And edit its content to change number of daemons (I use three):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==courier-imap==&lt;br /&gt;
&lt;br /&gt;
Edit the file &amp;lt;tt&amp;gt;/usr/lib/courier-imap/etc/imapd&amp;lt;/tt&amp;gt;, taking care to adapt &#039;&#039;&#039;IMAP_ULIMITD&#039;&#039;&#039; accordingly:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ADDRESS=127.0.0.1                    #Typ. use 0 or 127.0.0.1&lt;br /&gt;
...&lt;br /&gt;
IMAP_ULIMITD=2097152                 #Set same value as returned by &#039;ulimit -v&#039; or imapd.rc will complain&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Start-up Scripts==&lt;br /&gt;
&lt;br /&gt;
Create link to authlib and imap daemon in &amp;lt;tt&amp;gt;/etc/rc.d/init.d&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ln -s /usr/local/sbin/authdaemond /etc/rc.d/init.d/courier-authdaemon&lt;br /&gt;
ln -s /usr/lib/courier-imap/libexec/imapd.rc /etc/rc.d/init.d/courier-imap&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. &amp;lt;tt&amp;gt;[http://linux.die.net/man/8/makeuserdb man makeuserdb]&amp;lt;/tt&amp;gt; for details.&lt;br /&gt;
&lt;br /&gt;
First create user mailbox (replace &#039;&#039;username&#039;&#039; with user account name) with &amp;lt;tt&amp;gt;maildirmake&amp;lt;/tt&amp;gt;. Repeat for all users:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /home/username                          #if don&#039;t exist yet...&lt;br /&gt;
cd /home/username&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake ~username/MailDir/$i; done&lt;br /&gt;
# Create also default Maildir for new users&lt;br /&gt;
for i in &amp;quot;&amp;quot; .Drafts .Sent .Trash .Templates; do /usr/lib/courier-imap/bin/maildirmake /etc/skel/MailDir/$i; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next create the user authentication database &amp;lt;tt&amp;gt;/usr/local/etc/authlib/userdb&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch /usr/local/etc/authlib/userdb&lt;br /&gt;
chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
#Repeat for each username:&lt;br /&gt;
pw2userdb | grep &amp;quot;^username&amp;quot;&amp;gt;&amp;gt;/usr/local/etc/authlib/userdb   # Fill userdb from /etc/passwd user entry&lt;br /&gt;
userdb username set mail=~username/MailDir                    # Specify user MailDir location&lt;br /&gt;
userdbpw | userdb username set systempw                       # Set user account password&lt;br /&gt;
...&lt;br /&gt;
makeuserdb                                                    # Create binary database&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5296</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5296"/>
		<updated>2008-11-07T09:39:36Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Building and Installing Courier-IMAP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-imap-4.4.1.tar.bz2&lt;br /&gt;
$ cd courier-imap-4.4.1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a walk or some coffee... and when ready build the package and install it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make install&lt;br /&gt;
$ make install-configure&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
==courier-authlib==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==courier-imap==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5295</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5295"/>
		<updated>2008-11-07T09:35:20Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Building and Installing Courier Authentication Library */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of &#039;&#039;Courier Authentication Library&#039;&#039; using the module &#039;&#039;&#039;userdb&#039;&#039;&#039; to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ tar -xvjf courier-authlib-0.61.0.tar.bz2&lt;br /&gt;
$ cd courier-authlib-0.61.0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation ([http://lists.cairographics.org/archives/cairo/2004-April/001125.html])&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;&#039;userdb&#039;&#039;&#039;. Replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
--without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
--with-mailgroup=mkgroup-l-d&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready build, check the result and install the libraries.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ make&lt;br /&gt;
$ make check&lt;br /&gt;
$ make install&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&lt;br /&gt;
Take a walk... and when ready execute the following command to build the package.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Time to go for some coffee... and then install the package with the usual&lt;br /&gt;
&lt;br /&gt;
 $ make install&lt;br /&gt;
 $ make install-configure&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
==courier-authlib==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==courier-imap==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5294</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5294"/>
		<updated>2008-11-07T09:26:40Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Prerequisites */ Cosmetics&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;patch&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;tar&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;make&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;gcc&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;crypt&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libgdbm-devel&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;libtool&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;inetutils&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;tt&amp;gt;cygrunsrv&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of Courier Authentication Library using the module userdb to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
Solution source: http://lists.cairographics.org/archives/cairo/2004-April/001125.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;userdb&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
 --without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
 --with-mailgroup=mkgroup-l-d&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready execute the following command.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Take again a long pause... then check the result and install the libraries&lt;br /&gt;
&lt;br /&gt;
 $ make check&lt;br /&gt;
 $ make install&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&lt;br /&gt;
Take a walk... and when ready execute the following command to build the package.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Time to go for some coffee... and then install the package with the usual&lt;br /&gt;
&lt;br /&gt;
 $ make install&lt;br /&gt;
 $ make install-configure&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
==courier-authlib==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==courier-imap==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5293</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5293"/>
		<updated>2008-11-07T09:22:54Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Only reorganizing/renaming titles (no content changes)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Prerequisites=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* patch, tar, make, gcc&lt;br /&gt;
* crypt&lt;br /&gt;
* libgdbm-devel&lt;br /&gt;
* libtool&lt;br /&gt;
* inetutils&lt;br /&gt;
* cygrunsrv&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of Courier Authentication Library using the module userdb to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
Solution source: http://lists.cairographics.org/archives/cairo/2004-April/001125.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;userdb&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
 --without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
 --with-mailgroup=mkgroup-l-d&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready execute the following command.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Take again a long pause... then check the result and install the libraries&lt;br /&gt;
&lt;br /&gt;
 $ make check&lt;br /&gt;
 $ make install&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
=Building and Installing Courier-IMAP=&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&lt;br /&gt;
Take a walk... and when ready execute the following command to build the package.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Time to go for some coffee... and then install the package with the usual&lt;br /&gt;
&lt;br /&gt;
 $ make install&lt;br /&gt;
 $ make install-configure&lt;br /&gt;
&lt;br /&gt;
=Configuring Courier=&lt;br /&gt;
&lt;br /&gt;
==courier-authlib==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==courier-imap==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Configuration Summary==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Running=&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
=Testing=&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
=Installing as a Windows Service=&lt;br /&gt;
&lt;br /&gt;
==Startup Script==&lt;br /&gt;
&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin Service==&lt;br /&gt;
&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Other Interesting Packages=&lt;br /&gt;
&lt;br /&gt;
==Maildir==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
==Mairix - index and search mail folders==&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
==Offlineimap==&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5291</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5291"/>
		<updated>2008-11-06T13:28:50Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Running */ Typo and added &amp;quot;net start syslogd&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Pre-requisite=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* patch, tar, make, gcc&lt;br /&gt;
* crypt&lt;br /&gt;
* libgdbm-devel&lt;br /&gt;
* libtool&lt;br /&gt;
* inetutils&lt;br /&gt;
* cygrunsrv&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of Courier Authentication Library using the module userdb to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
==Compilation and installation==&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
Solution source: http://lists.cairographics.org/archives/cairo/2004-April/001125.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;userdb&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
 --without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
 --with-mailgroup=mkgroup-l-d&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready execute the following command.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Take again a long pause... then check the result and install the libraries&lt;br /&gt;
&lt;br /&gt;
 $ make check&lt;br /&gt;
 $ make install&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Running==&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
 $ net start syslogd&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemond stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
==Testing authlib==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
==Courier Authentication Config==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Courier-IMAP=&lt;br /&gt;
==Compilation and installation==&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&lt;br /&gt;
Take a walk... and when ready execute the following command to build the package.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Time to go for some coffee... and then install the package with the usual&lt;br /&gt;
&lt;br /&gt;
 $ make install&lt;br /&gt;
 $ make install-configure&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==Running==&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==All in one==&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin service==&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
=Maildir=&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
=Mairix - index and search mail folders=&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
=Offlineimap=&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator] character colon (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap.conf	2008-08-13 20:56:04.000000000 +0200&lt;br /&gt;
+++ offlineimap-cygwin.conf	2008-11-06 10:44:31.066750700 +0100&lt;br /&gt;
@@ -215,6 +215,19 @@&lt;br /&gt;
 &lt;br /&gt;
 restoreatime = no&lt;br /&gt;
 &lt;br /&gt;
+# Cygwin/Windows users may have issues with the Maildir mail filename&lt;br /&gt;
+# containing the suffix separator character (:). In this case, they&lt;br /&gt;
+# could change the suffix separator character to whatever required.&lt;br /&gt;
+# For example, Courier-IMAP for Cygwin is using (!)&lt;br /&gt;
+&lt;br /&gt;
+# suffixsep = !&lt;br /&gt;
+&lt;br /&gt;
+# Cygwin/Windows users may need to create Maildir mail filename in&lt;br /&gt;
+# binary mode. In this case, set the &#039;filemode&#039; to &#039;binary&#039;. Default is&lt;br /&gt;
+# &#039;text&#039;. Courier-IMAP for Cygwin works better with binary mode.&lt;br /&gt;
+&lt;br /&gt;
+# filemode = binary&lt;br /&gt;
+&lt;br /&gt;
 [Repository RemoteExample]&lt;br /&gt;
 &lt;br /&gt;
 # And this is the remote repository.  We only support IMAP or Gmail here.&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-08-13 20:55:48.000000000 +0200&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-06 10:44:05.344202700 +0100&lt;br /&gt;
@@ -23,7 +23,6 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -54,6 +53,12 @@&lt;br /&gt;
         self.messagelist = None&lt;br /&gt;
         self.repository = repository&lt;br /&gt;
         self.accountname = accountname&lt;br /&gt;
+        self.filemode = {&lt;br /&gt;
+          &#039;binary&#039;: &#039;wb&#039;,&lt;br /&gt;
+          &#039;text&#039;: &#039;wt&#039;,&lt;br /&gt;
+        }[repository.getconf(&amp;quot;filemode&amp;quot;, &#039;text&#039;)]&lt;br /&gt;
+        self.suffixsep = repository.getconf(&amp;quot;suffixsep&amp;quot;,&#039;:&#039;)&lt;br /&gt;
+        self.flagmatchre = re.compile(&#039;%s.*2,([A-Z]+)&#039; % self.suffixsep)&lt;br /&gt;
         BaseFolder.__init__(self)&lt;br /&gt;
 &lt;br /&gt;
     def getaccountname(self):&lt;br /&gt;
@@ -102,7 +107,7 @@&lt;br /&gt;
                     nouidcounter -= 1&lt;br /&gt;
                 else:&lt;br /&gt;
                     uid = long(uidmatch.group(1))&lt;br /&gt;
-            flagmatch = flagmatchre.search(messagename)&lt;br /&gt;
+            flagmatch = self.flagmatchre.search(messagename)&lt;br /&gt;
             flags = []&lt;br /&gt;
             if flagmatch:&lt;br /&gt;
                 flags = [x for x in flagmatch.group(1)]&lt;br /&gt;
@@ -180,7 +185,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), self.filemode)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +231,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = self.suffixsep&lt;br /&gt;
+        infomatch = re.search(&#039;(%s.*)$&#039; % self.suffixsep, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(self.suffixsep)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np0 &amp;lt; offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap. &#039;&#039;&#039;CAUTION:&#039;&#039;&#039; Add the NEW suffixsep and filemode options in the Maildir repository section of the configuration file.&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
suffixsep = !                    # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
filemode = binary                # &amp;lt;&amp;lt;&amp;lt; NEW&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5288</id>
		<title>Courier-Cygwin</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Courier-Cygwin&amp;diff=5288"/>
		<updated>2008-11-05T22:15:21Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: Fixed small typo (courrier -&amp;gt; courier)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Pre-requisite=&lt;br /&gt;
&lt;br /&gt;
Courier-IMAP requires the installation of the [http://www.courier-mta.org/authlib/ Courier Authentication Library] and the following cygwin tools and packages&lt;br /&gt;
&lt;br /&gt;
* patch, tar, make, gcc&lt;br /&gt;
* crypt&lt;br /&gt;
* libgdbm-devel&lt;br /&gt;
* libtool&lt;br /&gt;
* inetutils&lt;br /&gt;
* cygrunsrv&lt;br /&gt;
&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the required packages.&lt;br /&gt;
&lt;br /&gt;
=Courier Authentication Library=&lt;br /&gt;
&lt;br /&gt;
Installation of Courier Authentication Library using the module userdb to manage mail accounts. All other modules are disabled.&lt;br /&gt;
&lt;br /&gt;
==Compilation and installation==&lt;br /&gt;
&lt;br /&gt;
Download and untar [http://www.courier-mta.org/download.php#authlib courier-authlib] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-authlib-0.61.0.tar.bz2 0.61.0]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-authlib-0.61.0-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# add libtool flag (-no-undefined) required for DLL creation&lt;br /&gt;
# add missing dependencies&lt;br /&gt;
# add PATH in start script to access new DLL (installed in a different directory)&lt;br /&gt;
&lt;br /&gt;
Solution source: http://lists.cairographics.org/archives/cairo/2004-April/001125.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-authlib-0.61.0/makedat/Makefile.in	2008-05-24 16:21:09.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/makedat/Makefile.in	2008-10-21 16:02:38.709166700 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-authlib-0.61.0/Makefile.in	2008-07-12 21:41:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/Makefile.in	2008-10-23 22:59:03.843750000 +0200&lt;br /&gt;
@@ -213,9 +213,10 @@&lt;br /&gt;
 LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
 	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \&lt;br /&gt;
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)&lt;br /&gt;
-CCLD = $(CC)&lt;br /&gt;
+CCLD = $(CC) -no-undefined&lt;br /&gt;
+CCLDEXE = $(CC)&lt;br /&gt;
 LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \&lt;br /&gt;
-	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
+	--mode=link $(CCLDEXE) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \&lt;br /&gt;
 	$(LDFLAGS) -o $@&lt;br /&gt;
 SOURCES = $(libauthcustom_la_SOURCES) $(libauthldap_la_SOURCES) \&lt;br /&gt;
 	$(libauthmysql_la_SOURCES) $(libauthpam_la_SOURCES) \&lt;br /&gt;
@@ -452,9 +453,9 @@&lt;br /&gt;
 	README.authdebug.html&lt;br /&gt;
 &lt;br /&gt;
 DISTCLEANFILES = dbobj.config README_authlib.html&lt;br /&gt;
-commonlibdep = libcourierauthcommon.la&lt;br /&gt;
+commonlibdep = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 commonldflags = -module -rpath $(pkglibdir) -export-symbols-regex &#039;courier_auth.*_init&#039; -avoid-version&lt;br /&gt;
-commonlibadd = libcourierauthcommon.la&lt;br /&gt;
+commonlibadd = libcourierauthcommon.la libcourierauth.la&lt;br /&gt;
 libcourierauthcommon_t = @CRYPTLIBS@&lt;br /&gt;
 libcourierauthcommon_la_SOURCES = \&lt;br /&gt;
 	auth.h courierauth.h \&lt;br /&gt;
--- courier-authlib-0.61.0/authdaemond.in	2005-07-05 14:25:08.000000000 +0200&lt;br /&gt;
+++ courier-authlib-0.61.0-cygwin/authdaemond.in	2008-10-25 12:03:32.140625000 +0200&lt;br /&gt;
@@ -15,4 +15,10 @@&lt;br /&gt;
 set -a&lt;br /&gt;
 . @authdaemonrc@&lt;br /&gt;
 &lt;br /&gt;
+# Some shared libraries (DLL) are installed in @libdir@/bin&lt;br /&gt;
+# instead of @libdir@/@PACKAGE@&lt;br /&gt;
+# Setting LD_LIBRARY_PATH at runtime or LR_RUN_PATH at linktime doesn&#039;t&lt;br /&gt;
+# work in cygwin, only setting PATH works. &lt;br /&gt;
+export PATH=$PATH:@libdir@/bin&lt;br /&gt;
+&lt;br /&gt;
 exec ${sbindir}/courierlogger -pid=@authdaemonvar@/pid $LOGGEROPTS -$1 @libexecdir@/courier-authlib/authdaemond&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-authlib-0.61.0-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package without most authentication modules, keeping only &#039;&#039;userdb&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: replace &#039;&#039;mailuser&#039;&#039; by an existing user name (in your /etc/passwd file). I used my own username.&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait --without-authpam --without-authldap --without-authpwd \&lt;br /&gt;
 --without-authshadow --without-authcustom --without-authpipe --without-authmysql --without-authpgsql --with-mailuser=mailuser \&lt;br /&gt;
 --with-mailgroup=mkgroup-l-d&lt;br /&gt;
&lt;br /&gt;
Take a long pause... and when ready execute the following command.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Take again a long pause... then check the result and install the libraries&lt;br /&gt;
&lt;br /&gt;
 $ make check&lt;br /&gt;
 $ make install&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;: list of related topics found during investigation for compilation&lt;br /&gt;
* authldap: configure: error: -lresolve is needed for res_query... http://www.cygwin.com/ml/cygwin/2005-04/msg00419.html&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
&lt;br /&gt;
Create authdaemonrc file: /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
 $ cp /usr/local/etc/authlib/authdaemonrc.dist /usr/local/etc/authlib/authdaemonrc&lt;br /&gt;
&lt;br /&gt;
Change number of daemons (I use three) and enable DEBUG_LOGIN&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
# The number of daemon processes that are started.&lt;br /&gt;
daemons=3&lt;br /&gt;
&lt;br /&gt;
# DEBUG_LOGIN=2   - turn on debugging + log passwords too&lt;br /&gt;
DEBUG_LOGIN=2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See http://www.courier-mta.org/authlib/README.authdebug.html for details.&lt;br /&gt;
&lt;br /&gt;
==IMAP accounts==&lt;br /&gt;
&lt;br /&gt;
User accounts and settings are managed by &#039;&#039;userdb&#039;&#039;. See [http://linux.die.net/man/8/makeuserdb makeuserdb] man page for details, or used the freshly new install man page - man makeuserdb&lt;br /&gt;
&lt;br /&gt;
Assuming &#039;&#039;username&#039;&#039; is your username, 1001 and 10545 are respectively the UID and GID of an existing user (part of your /etc/passwd and /etc/group). I use my own UID and GID. Create the mailuser home directory, if required, and create Maildir folder.&lt;br /&gt;
&lt;br /&gt;
 $ mkdir -p /home/username&lt;br /&gt;
 $ cd /home/username&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake Maildir&lt;br /&gt;
&lt;br /&gt;
Create the userdb text file /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
 $ touch /usr/local/etc/authlib/userdb&lt;br /&gt;
 $ chmod 700 /usr/local/etc/authlib/userdb&lt;br /&gt;
&lt;br /&gt;
Edit /usr/local/etc/authlib/userdb, one line per account&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
username[TAB]uid=1001|gid=10111|home=/home/username|mail=/home/username/Maildir|systempw=XXXXXX&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where XXXXXX is the encrypted password created with&lt;br /&gt;
&lt;br /&gt;
 $  /usr/local/sbin/userdbpw.exe&lt;br /&gt;
&lt;br /&gt;
Create the (binary) userdb&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/makeuserdb&lt;br /&gt;
&lt;br /&gt;
You should now have the following files created:&lt;br /&gt;
&lt;br /&gt;
* /usr/local/etc/authlib/userdb.dat&lt;br /&gt;
* /usr/local/etc/authlib/userdbshadow.dat&lt;br /&gt;
&lt;br /&gt;
==Running==&lt;br /&gt;
&lt;br /&gt;
Install and configure syslogd. Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install inetutils (contains syslogd). Configure syslogd with the following command. It will create the /etc/syslogd.conf file and install a windows service using cygrunsrv&lt;br /&gt;
&lt;br /&gt;
 $ syslogd-config&lt;br /&gt;
&lt;br /&gt;
Start the authlib daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemon start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authdaemon stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
==Testing authlib==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/sbin/authtest username CCCCCC&lt;br /&gt;
 Authentication succeeded.&lt;br /&gt;
 &lt;br /&gt;
      Authenticated: username  (uid 1001, gid 10545)&lt;br /&gt;
     Home Directory: /home/username&lt;br /&gt;
            Maildir: /home/username/Maildir&lt;br /&gt;
              Quota: (none)&lt;br /&gt;
 Encrypted Password: XXXXXX&lt;br /&gt;
 Cleartext Password: CCCCCC&lt;br /&gt;
            Options: (none)&lt;br /&gt;
&lt;br /&gt;
where username is your user name and XXXXXX is your encrypted password as provided in &#039;&#039;/usr/local/etc/authlib/userdb&#039;&#039;. CCCCCC is your password in clear.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
Should you have a doubt on the execution of a command (ie: no output) you can check if the application is able to load required DLL. This error is not reported. Using &#039;&#039;strace&#039;&#039;, windows will complain about DLL not found, if any. To solve this problem you may need to add some path in your PATH. For example, in order to test authlib with authtest:&lt;br /&gt;
&lt;br /&gt;
 $ strace /usr/local/sbin/authtest&lt;br /&gt;
     # This will open a dialog box to complain about DLL.&lt;br /&gt;
 $ export PATH=$PATH:/usr/local/lib/bin&lt;br /&gt;
 $ /usr/local/sbin/authtest ausername&lt;br /&gt;
&lt;br /&gt;
==Courier Authentication Config==&lt;br /&gt;
&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --version&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --ldflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --cppflags&lt;br /&gt;
 $ /usr/local/bin/courierauthconfig.exe --configfiles&lt;br /&gt;
&lt;br /&gt;
=Courier-IMAP=&lt;br /&gt;
==Compilation and installation==&lt;br /&gt;
&lt;br /&gt;
Download and untar package [http://www.courier-mta.org/download.php#imap courier-imap] in your favorite sandbox.&lt;br /&gt;
Version used: [http://prdownloads.sourceforge.net/courier/courier-imap-4.4.1.tar.bz2 4.4.1.20080920]&lt;br /&gt;
&lt;br /&gt;
Apply the [{{#file:courier-imap-4.4.1-cygwin.patch}} patch] before configuration to correct following issues:&lt;br /&gt;
&lt;br /&gt;
# incorrect usage of EXEEXT in &#039;&#039;makedat/Makefile&#039;&#039;&lt;br /&gt;
# incorrect usage of EXTEXT in main &#039;&#039;Makefile&#039;&#039;&lt;br /&gt;
# remove usage of /usr/lib/env in start/stop script (/usr/lib/env does not seem to work under Cygwin)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/makedat/Makefile.in	2008-08-24 19:52:51.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/makedat/Makefile.in	2008-10-21 20:43:27.500000000 +0200&lt;br /&gt;
@@ -182,7 +182,7 @@&lt;br /&gt;
 libexecdir = @libexecdir@&lt;br /&gt;
 localedir = @localedir@&lt;br /&gt;
 localstatedir = @localstatedir@&lt;br /&gt;
-makedatprog_target = @makedatprog_target@&lt;br /&gt;
+makedatprog_target = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprogpath = @makedatprogpath@&lt;br /&gt;
 mandir = @mandir@&lt;br /&gt;
 mkdir_p = @mkdir_p@&lt;br /&gt;
@@ -198,7 +198,7 @@&lt;br /&gt;
 target_alias = @target_alias@&lt;br /&gt;
 top_builddir = @top_builddir@&lt;br /&gt;
 top_srcdir = @top_srcdir@&lt;br /&gt;
-noinst_PROGRAMS = @makedatprog_target@&lt;br /&gt;
+noinst_PROGRAMS = @makedatprog_target@$(EXEEXT)&lt;br /&gt;
 makedatprog_SOURCES = makedatprog.c&lt;br /&gt;
 makedatprog_DEPENDENCIES = @dblibrary@&lt;br /&gt;
 makedatprog_LDADD = @dblibrary@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/Makefile.in	2008-09-20 14:48:46.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/Makefile.in	2008-10-21 20:59:45.156250000 +0200&lt;br /&gt;
@@ -247,9 +247,9 @@&lt;br /&gt;
 CLEANFILES = $(databin_SCRIPTS) $(man_MANS) $(sysconf_DATA) $(sbin_SCRIPTS)&lt;br /&gt;
 databindir = $(datadir)&lt;br /&gt;
 databin_SCRIPTS = mkimapdcert mkpop3dcert&lt;br /&gt;
-binPROGRAMS = imapd pop3d maildirmake maildiracl deliverquota maildirkw&lt;br /&gt;
-sbinPROGRAMS = imaplogin pop3login&lt;br /&gt;
-libexecPROGRAMS = makedatprog couriertcpd&lt;br /&gt;
+binPROGRAMS = imapd$(EXEEXT) pop3d$(EXEEXT) maildirmake$(EXEEXT) maildiracl$(EXEEXT) deliverquota$(EXEEXT) maildirkw$(EXEEXT)&lt;br /&gt;
+sbinPROGRAMS = imaplogin$(EXEEXT) pop3login$(EXEEXT)&lt;br /&gt;
+libexecPROGRAMS = makedatprog$(EXEEXT) couriertcpd$(EXEEXT)&lt;br /&gt;
 bin_PROGRAMS = @binPROGRAMS_exec@&lt;br /&gt;
 sbin_PROGRAMS = @sbinPROGRAMS_exec@&lt;br /&gt;
 libexec_PROGRAMS = @libexecPROGRAMS_exec@&lt;br /&gt;
--- courier-imap-4.4.1.20080920/imapd.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/imapd.rc.in	2008-10-26 10:17:51.359375000 +0100&lt;br /&gt;
@@ -22,6 +22,15 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 TLS_CACHEFILE=&amp;quot;&amp;quot;&lt;br /&gt;
 . @sysconfdir@/imapd-ssl&lt;br /&gt;
 . @sysconfdir@/imapd&lt;br /&gt;
@@ -35,7 +44,7 @@&lt;br /&gt;
 &lt;br /&gt;
 	umask $IMAP_UMASK&lt;br /&gt;
 	@ULIMIT@ $IMAP_ULIMITD&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 			prefix=@prefix@ ;&lt;br /&gt;
 			exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 			bindir=@bindir@ ;&lt;br /&gt;
--- courier-imap-4.4.1.20080920/pop3d.rc.in	2008-05-04 15:12:47.000000000 +0200&lt;br /&gt;
+++ courier-imap-4.4.1.20080920-cygwin/pop3d.rc.in	2008-10-26 10:18:02.187500000 +0100&lt;br /&gt;
@@ -22,12 +22,21 @@&lt;br /&gt;
 	exit 1&lt;br /&gt;
 fi&lt;br /&gt;
 &lt;br /&gt;
+# Location for some shared libraries (cygcourierauth*.dll) from authlib&lt;br /&gt;
+AUTHLIBDIR=/usr/local&lt;br /&gt;
+if test ! -f $AUTHLIBDIR/lib/bin/cygcourierauth.dll&lt;br /&gt;
+then&lt;br /&gt;
+	echo &amp;quot;$AUTHLIBDIR/lib/bin/cygcourierauth.dll not found.&amp;quot;&lt;br /&gt;
+	exit 1&lt;br /&gt;
+fi&lt;br /&gt;
+export PATH=$PATH:$AUTHLIBDIR/lib/bin&lt;br /&gt;
+&lt;br /&gt;
 . @sysconfdir@/pop3d-ssl&lt;br /&gt;
 . @sysconfdir@/pop3d&lt;br /&gt;
 &lt;br /&gt;
 case $1 in&lt;br /&gt;
 start)&lt;br /&gt;
-	@SETENV@ -i @SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
+	@SHELL@ -c &amp;quot; set -a ;&lt;br /&gt;
 		prefix=@prefix@ ;&lt;br /&gt;
 		exec_prefix=@exec_prefix@ ;&lt;br /&gt;
 		bindir=@bindir@ ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Install the patch&lt;br /&gt;
&lt;br /&gt;
 $ patch -Np1 &amp;lt; courier-imap-4.4.1-cygwin.patch&lt;br /&gt;
&lt;br /&gt;
Configure the package&lt;br /&gt;
&lt;br /&gt;
 $ ./configure --disable-root-check --with-waitfunc=wait&lt;br /&gt;
&lt;br /&gt;
Take a walk... and when ready execute the following command to build the package.&lt;br /&gt;
&lt;br /&gt;
 $ make&lt;br /&gt;
&lt;br /&gt;
Time to go for some coffee... and then install the package with the usual&lt;br /&gt;
&lt;br /&gt;
 $ make install&lt;br /&gt;
 $ make install-configure&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
&lt;br /&gt;
Setup courier-imap: $prefix/etc/imapd (where $prefix=/usr/lib/courier-imap)&lt;br /&gt;
&lt;br /&gt;
Set ADDRESS to a valid value (0 or 127.0.0.1) and change IMAP_ULIMITD to a value accepted by the command ulimit. I simply used the existing value returned by&lt;br /&gt;
&lt;br /&gt;
 $ ulimit -v&lt;br /&gt;
&lt;br /&gt;
==Running==&lt;br /&gt;
&lt;br /&gt;
Syslogd service and authdaemond should be started. See above.&lt;br /&gt;
&lt;br /&gt;
Start the imap daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc start&lt;br /&gt;
&lt;br /&gt;
Stop the daemon with the following command:&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/libexec/imapd.rc stop&lt;br /&gt;
&lt;br /&gt;
You&#039;ll find log messages in /var/log/messages (default target file as specified in /etc/syslogd.conf)&lt;br /&gt;
&lt;br /&gt;
==Testing==&lt;br /&gt;
When authdaemond and imapd are running you can do a simple login test:&lt;br /&gt;
&lt;br /&gt;
 $ telnet localhost 143&lt;br /&gt;
&lt;br /&gt;
and type the login command&lt;br /&gt;
&lt;br /&gt;
 a login &amp;lt;username&amp;gt; &amp;lt;password&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the server should reply&lt;br /&gt;
&lt;br /&gt;
 a OK LOGIN Ok.&lt;br /&gt;
&lt;br /&gt;
to which you can reply with a logout&lt;br /&gt;
&lt;br /&gt;
 a logout&lt;br /&gt;
&lt;br /&gt;
the session is terminated by the server&lt;br /&gt;
&lt;br /&gt;
 * BYE Courier-IMAP server shutting down&lt;br /&gt;
 a OK LOGOUT completed&lt;br /&gt;
 Connection closed by foreign host.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hint:&#039;&#039;&#039; if the connection is immediately closed by foreign host it probably means that &#039;&#039;imapd&#039;&#039; does not have access to all required DLLs. Check your PATH.&lt;br /&gt;
&lt;br /&gt;
==All in one==&lt;br /&gt;
If everything works fine you can use the following [{{#file:imapd}} startup script] to launch or stop imap and authlib daemons. It can be saved in /usr/local/sbin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
#&lt;br /&gt;
# Courier imap daemon startup script.&lt;br /&gt;
&lt;br /&gt;
authlib=/usr/local/sbin/authdaemond&lt;br /&gt;
imapd=/usr/lib/courier-imap/libexec/imapd.rc&lt;br /&gt;
&lt;br /&gt;
test ! -f $authlib &amp;amp;&amp;amp; echo &amp;quot;File not found: $authlib&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
test ! -f $imapd &amp;amp;&amp;amp; echo &amp;quot;File not found: $imapd&amp;quot; &amp;amp;&amp;amp; exit 1;&lt;br /&gt;
&lt;br /&gt;
case $1 in&lt;br /&gt;
	start)&lt;br /&gt;
		$authlib start&lt;br /&gt;
		$imapd start&lt;br /&gt;
		;;&lt;br /&gt;
	stop)&lt;br /&gt;
		$imapd stop&lt;br /&gt;
		$authlib stop&lt;br /&gt;
		;;&lt;br /&gt;
	*)&lt;br /&gt;
		echo &amp;quot;Usage: $0 &amp;lt;start|stop&amp;gt;&amp;quot;&lt;br /&gt;
		;;&lt;br /&gt;
esac&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Cygwin service==&lt;br /&gt;
Create the [{{#file:imapd-srv.sh}} service script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
#!/bin/sh&lt;br /&gt;
# File:     imapd-service.sh&lt;br /&gt;
# Purpose:  Courier imap daemon service script.&lt;br /&gt;
#&lt;br /&gt;
# NOTE:     This script must be excutable by SYSTEM&lt;br /&gt;
username=username	# &amp;lt;&amp;lt;&amp;lt;&amp;lt; Change me !!!&lt;br /&gt;
pidsleep=&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Function to handle QUIT signal.&lt;br /&gt;
# Stop imapd daemon and kill background sleep.&lt;br /&gt;
function handleQuit&lt;br /&gt;
{&lt;br /&gt;
	echo &amp;quot;STOPPING: /usr/local/sbin/imapd&amp;quot;&lt;br /&gt;
	su $username -c &amp;quot;/usr/local/sbin/imapd stop&amp;quot;&lt;br /&gt;
	test -n &amp;quot;$pidsleep&amp;quot; &amp;amp;&amp;amp; kill -9 $pidsleep&lt;br /&gt;
	exit&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Interruptible sleep&lt;br /&gt;
# Note: sleep is an external command (not builtin command), hence&lt;br /&gt;
#       not interruptible by the QUIT signal.&lt;br /&gt;
function intsleep&lt;br /&gt;
{&lt;br /&gt;
	sleep $1 &amp;amp;&lt;br /&gt;
	pidsleep=$!&lt;br /&gt;
	wait $pidsleep&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;STARTING: /usr/local/sbin/imapd as $username at &amp;quot;`date`&lt;br /&gt;
su $username -c &amp;quot;/usr/local/sbin/imapd start&amp;quot;&lt;br /&gt;
&lt;br /&gt;
trap &amp;quot;handleQuit&amp;quot; SIGQUIT&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;WAITING: &amp;quot;$$&lt;br /&gt;
while true; do intsleep 1d; done&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Change username and save it to your favorite location, says /usr/local/sbin. The service script must be executable by SYSTEM, ie: the user that run the windows services.&lt;br /&gt;
&lt;br /&gt;
 $ chmod +rx /usr/local/sbin/imapd-service.sh&lt;br /&gt;
&lt;br /&gt;
Install the new service with the following command.&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --install imapd --desc &amp;quot;Courier IMAP daemon&amp;quot; --disp &amp;quot;CYGWIN imapd&amp;quot; \&lt;br /&gt;
   --path /usr/local/sbin/imapd-service.sh --termsig QUIT --type auto --shutdown&lt;br /&gt;
&lt;br /&gt;
Finally, just start the service&lt;br /&gt;
&lt;br /&gt;
 $ cygrunsrv --start imapd&lt;br /&gt;
 or&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
&lt;br /&gt;
You should now have couple of processes related to courier-imap&lt;br /&gt;
&lt;br /&gt;
 $ ps -a&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTES&#039;&#039;&#039;:&lt;br /&gt;
* If the service could not be started, it&#039;s probably because the service script is not executable by SYSTEM&lt;br /&gt;
&lt;br /&gt;
 $ net start imapd&lt;br /&gt;
 The CYGWIN imapd service is starting.&lt;br /&gt;
 The CYGWIN imapd service could not be started. &lt;br /&gt;
 &lt;br /&gt;
 The service did not report an error.&lt;br /&gt;
 &lt;br /&gt;
 More help is available by typing NET HELPMSG 3534.&lt;br /&gt;
&lt;br /&gt;
* The combination of background sleep and builtin wait command is used to make the waiting statment interruptible. The original script found on the net, was simply using a &#039;sleep 1&#039; which turned to consume ~10% of the CPU.&lt;br /&gt;
&lt;br /&gt;
=Maildir=&lt;br /&gt;
&#039;&#039;&#039;maildirmake&#039;&#039;&#039; is part of the courier-imap package&lt;br /&gt;
&lt;br /&gt;
 $ /usr/lib/courier-imap/bin/maildirmake&lt;br /&gt;
&lt;br /&gt;
=Mairix - index and search mail folders=&lt;br /&gt;
Run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package mairix.&lt;br /&gt;
&lt;br /&gt;
Create the configuration file in your home directory: ~/.mairixrc&lt;br /&gt;
&lt;br /&gt;
 base=/home/username&lt;br /&gt;
 maildir=Maildir...&lt;br /&gt;
 omit=Maildir/.Mairix**&lt;br /&gt;
 mfolder=Maildir/.Mairix&lt;br /&gt;
 database=/home/username/.mairix_database&lt;br /&gt;
&lt;br /&gt;
The create the mairix index&lt;br /&gt;
&lt;br /&gt;
 $ mairix&lt;br /&gt;
 and&lt;br /&gt;
 $ mairix --fast-index  # on daily base&lt;br /&gt;
&lt;br /&gt;
See [[Mail_Tips]] for additional details.&lt;br /&gt;
&lt;br /&gt;
=Offlineimap=&lt;br /&gt;
Requires python, so run the [http://www.cygwin.com/setup.exe Cygwin setup] program. Locate, select and install the package python.&lt;br /&gt;
&lt;br /&gt;
Download offlineimap [http://software.complete.org/software/projects/list_files/offlineimap here]. I use [http://software.complete.org/software/versions/download/242?attachment_id=334 version 6.0.3]. Extract files in you favorite sandbox.&lt;br /&gt;
&lt;br /&gt;
 $ tar xvfz offlineimap_6.0.3.tar.gz&lt;br /&gt;
 $ cd offlineimap&lt;br /&gt;
&lt;br /&gt;
Apply the following [{{#file:offlineimap_6.0.3-cygwin.patch}} patch] to correct the following issues:&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Maildir#Windows_software Suffix separator character] (:) is not allowed in Windows. Courier-imap for cygwin is using (!)&lt;br /&gt;
* While used by courier-imap for cygwin Maildir mail files should not use CRLF, rather only LF. The issue appears only in mail with attachment, that is the raw message is not interpreted and displayed as it in the mail body (under Thunderbird).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=diff&amp;gt;&lt;br /&gt;
--- offlineimap/folder/Maildir.py	2008-11-01 20:49:30.843750000 +0100&lt;br /&gt;
+++ offlineimap/folder/Maildir-cygwin.py	2008-11-03 22:54:51.437500000 +0100&lt;br /&gt;
@@ -23,7 +23,7 @@&lt;br /&gt;
 import os.path, os, re, time, socket, md5&lt;br /&gt;
 &lt;br /&gt;
 uidmatchre = re.compile(&#039;,U=(\d+)&#039;)&lt;br /&gt;
-flagmatchre = re.compile(&#039;:.*2,([A-Z]+)&#039;)&lt;br /&gt;
+flagmatchre = re.compile(&#039;!.*2,([A-Z]+)&#039;)&lt;br /&gt;
 &lt;br /&gt;
 timeseq = 0&lt;br /&gt;
 lasttime = long(0)&lt;br /&gt;
@@ -180,7 +180,7 @@&lt;br /&gt;
                 break&lt;br /&gt;
         tmpmessagename = messagename.split(&#039;,&#039;)[0]&lt;br /&gt;
         ui.debug(&#039;maildir&#039;, &#039;savemessage: using temporary name %s&#039; % tmpmessagename)&lt;br /&gt;
-        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wt&amp;quot;)&lt;br /&gt;
+        file = open(os.path.join(tmpdir, tmpmessagename), &amp;quot;wb&amp;quot;)&lt;br /&gt;
         file.write(content)&lt;br /&gt;
 &lt;br /&gt;
         # Make sure the data hits the disk&lt;br /&gt;
@@ -226,11 +226,11 @@&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;cur&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             newpath = os.path.join(self.getfullname(), &#039;new&#039;)&lt;br /&gt;
-        infostr = &#039;:&#039;&lt;br /&gt;
-        infomatch = re.search(&#039;(:.*)$&#039;, newname)&lt;br /&gt;
+        infostr = &#039;!&#039;&lt;br /&gt;
+        infomatch = re.search(&#039;(!.*)$&#039;, newname)&lt;br /&gt;
         if infomatch:                   # If the info string is present..&lt;br /&gt;
             infostr = infomatch.group(1)&lt;br /&gt;
-            newname = newname.split(&#039;:&#039;)[0] # Strip off the info string.&lt;br /&gt;
+            newname = newname.split(&#039;!&#039;)[0] # Strip off the info string.&lt;br /&gt;
         infostr = re.sub(&#039;2,[A-Z]*&#039;, &#039;&#039;, infostr)&lt;br /&gt;
         flags.sort()&lt;br /&gt;
         infostr += &#039;2,&#039; + &#039;&#039;.join(flags)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 $ cd offlineimap/folder&lt;br /&gt;
 $ patch -Np2 &amp;lt; ../../offlineimap_6.0.3-cygwin.patch&lt;br /&gt;
 $ cd ../..&lt;br /&gt;
&lt;br /&gt;
Install offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ python setup.py install&lt;br /&gt;
&lt;br /&gt;
Configure offlineimap as described in [[Offlineimap]] and launch offlineimap&lt;br /&gt;
&lt;br /&gt;
 $ offlineimap&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -1 -o -u Noninteractive.Basic&lt;br /&gt;
 or&lt;br /&gt;
 $ offlineimap -c /home/username/offlineimap.conf&lt;br /&gt;
&lt;br /&gt;
Here is a simple [{{#file:offlineimap.conf}} offlineimap configuration file].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=text&amp;gt;&lt;br /&gt;
[general]&lt;br /&gt;
metadata = /home/username/.offlineimap&lt;br /&gt;
accounts = Test&lt;br /&gt;
maxsyncaccounts = 1&lt;br /&gt;
ui = Curses.Blinkenlights, TTY.TTYUI,&lt;br /&gt;
     Noninteractive.Basic, Noninteractive.Quiet&lt;br /&gt;
ignore-readonly = no&lt;br /&gt;
&lt;br /&gt;
[mbnames]&lt;br /&gt;
enabled = no&lt;br /&gt;
&lt;br /&gt;
[ui.Curses.Blinkenlights]&lt;br /&gt;
statuschar = .&lt;br /&gt;
&lt;br /&gt;
[Account Test]&lt;br /&gt;
localrepository = LocalExample&lt;br /&gt;
remoterepository = RemoteExample&lt;br /&gt;
&lt;br /&gt;
[Repository LocalExample]&lt;br /&gt;
type = Maildir&lt;br /&gt;
localfolders = /home/username/Maildir&lt;br /&gt;
sep = .&lt;br /&gt;
restoreatime = no&lt;br /&gt;
&lt;br /&gt;
[Repository RemoteExample]&lt;br /&gt;
type = IMAP&lt;br /&gt;
remotehost = imapserver&lt;br /&gt;
ssl = no&lt;br /&gt;
remoteport = 143&lt;br /&gt;
remoteuser = username&lt;br /&gt;
remotepass = XXXXXX&lt;br /&gt;
maxconnections = 1&lt;br /&gt;
holdconnectionopen = no&lt;br /&gt;
nametrans = lambda foldername: re.sub(&#039;^INBOX\.*&#039;, &#039;.&#039;, foldername)&lt;br /&gt;
folderfilter = lambda foldername: not re.search(&#039;(SPAM$|Mairix)&#039;, foldername)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=MiscCrypto&amp;diff=5112</id>
		<title>MiscCrypto</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=MiscCrypto&amp;diff=5112"/>
		<updated>2008-10-09T10:00:50Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* To unlock password-protected pdfs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Under Windows==&lt;br /&gt;
===[http://www.cryptool.com/ CryptTool]===&lt;br /&gt;
* Demonstration and Reference Program for Cryptography + making AES executables&lt;br /&gt;
* freeware&lt;br /&gt;
===[http://axcrypt.sourceforge.net/ AxCrypt]===&lt;br /&gt;
* AES-128 File Encryption, Compression and double-click Edit/View for secure document storage on Windows 95/98/ME/NT/2K/XP, locally or remote.&lt;br /&gt;
* GPL&lt;br /&gt;
===[http://www.chilkatsoft.com/ChilkatSfx.asp Zip 2 Secure EXE]===&lt;br /&gt;
* AES-128/192/256 bits File Encryption, Create self-extracting EXE files from zip files&lt;br /&gt;
* freeware&lt;br /&gt;
==[[LoopCrypt]]==&lt;br /&gt;
==[[Encfs]]==&lt;br /&gt;
==[[TrueCrypt]]==&lt;br /&gt;
==[[LUKS]]==&lt;br /&gt;
&lt;br /&gt;
==Misc==&lt;br /&gt;
===To unlock password-protected pdfs===&lt;br /&gt;
* PDF documents may have up to 2 passwords:&lt;br /&gt;
** &#039;&#039;&#039;User password&#039;&#039;&#039;: protects read access to the document, and when no &#039;&#039;Owner password&#039;&#039; is specified, also protects permission settings.&lt;br /&gt;
** &#039;&#039;&#039;Owner password&#039;&#039;&#039;: protects full access to the document, and protects permission settings (printing, copying...)&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;pdftops&amp;lt;/tt&amp;gt; to convert a protected PDF to Postscript, and possibly combine it with &amp;lt;tt&amp;gt;ps2pdf&amp;lt;/tt&amp;gt; to obtain an unrestricted pdf. Knowing the &#039;&#039;Owner password&#039;&#039; is the easiest since that allows removing all restrictions. If not, it also works but in that case the permission &amp;lt;tt&amp;gt;allow Printing&amp;lt;/tt&amp;gt; must be set. If it is not the case, then &#039;&#039;Owner password&#039;&#039; is necessary. Also if &#039;&#039;User password&#039;&#039; is set (ie. pdf reader asks for a password at open), then it must be provided (providing &#039;&#039;Owner password&#039;&#039; is also ok of course).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get install gs-common xpdf-utils&lt;br /&gt;
pdftops &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps                              # Owner pwd set but unknown and &#039;allow printing&#039; set&lt;br /&gt;
pdftops -upw &amp;lt;userpwd&amp;gt; &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps               # Same as above but user password also set&lt;br /&gt;
pdftops -opw &amp;lt;ownerpwd&amp;gt; &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps              # &#039;allow printing&#039; not set -&amp;gt; owner pwd is necessary&lt;br /&gt;
&lt;br /&gt;
pdftops -upw &amp;lt;password&amp;gt; &amp;lt;encrypted&amp;gt;.pdf -|ps2pdf - &amp;lt;decrypted&amp;gt;.pdf  # To generate a new PDF immediately&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An other solution is to use &#039;&#039;PDF Toolkit&#039;&#039; &amp;lt;tt&amp;gt;pdftk&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;apt-get install pdftk&amp;lt;/tt&amp;gt;). However unlike &#039;&#039;pdftops&#039;&#039; this method doesn&#039;t work when only &#039;&#039;user password&#039;&#039; is known but both passwords are set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;pdftk &amp;lt;encrypted&amp;gt;.pdf input_pw &amp;lt;password&amp;gt; output &amp;lt;decrypted&amp;gt;.pdf&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pdftk&amp;lt;/tt&amp;gt; can also be used to generate protected documents, and specifying permissions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pdftk &amp;lt;unprotected&amp;gt;.pdf output &amp;lt;protected&amp;gt;.pdf allow Printing owner_pw &amp;lt;ownerpwd&amp;gt; user_pw &amp;lt;userpwd&amp;gt;    #Allow HQ printing&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===pwsafe===&lt;br /&gt;
To use &#039;secure ram&#039; (thereby locking the data in memory and preventing it being flushed to disk) you may like to run it setuid root:&lt;br /&gt;
 $ sudo dpkg-statoverride --update --add --force root root 4755 /usr/bin/pwsafe&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Outlook&amp;diff=5109</id>
		<title>Outlook</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Outlook&amp;diff=5109"/>
		<updated>2008-10-07T14:01:07Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Macro Send &amp;amp; Save */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A page about Outlook on this wiki? Sounds weird isn&#039;t it?&lt;br /&gt;
&amp;lt;br&amp;gt;Well, blame my employer.&lt;br /&gt;
&lt;br /&gt;
We migrated from Lotus Notes, with crappy hacked outdated client so Outlook is still better but...&lt;br /&gt;
&amp;lt;br&amp;gt;At least under Lotus Notes it was possible to add an IMAP account (BTW Lotus Notes crashed quite often when talking IMAP...)&lt;br /&gt;
&amp;lt;br&amp;gt;Here: Tools-&amp;gt;Account Settings-&amp;gt;&#039;&#039;This feature has been disabled by your system administrator&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
* Microsoft Office 2007 Resource Kit (official documentation from Microsoft)&lt;br /&gt;
** [http://technet.microsoft.com/en-gb/library/cc178979.aspx Documentation page]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkId=85671 Security for the 2007 Office release]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkID=94264 Group Policy overview for the 2007 Office release]&lt;br /&gt;
** [http://go.microsoft.com/fwlink/?LinkId=78161 Administrative template (ADM,ADMX,...) files]&lt;br /&gt;
*** Use [http://www.7-zip.org/ 7-zip] to decompress this file without installing it. Don&#039;t miss the summary excel sheet inside.&lt;br /&gt;
* &#039;&#039;Configuring Microsoft Outlook 2003&#039;&#039;, By Sue Mosher, Robert Sparnaaij, Charlie Pulfer, David Hooker.&lt;br /&gt;
** Excellent book for administering Outlook 2003. Content can be browsed/searched on [http://books.google.com/books?id=v8oZNEByTR0C Google Books].&lt;br /&gt;
* Excellent 3rd party page on Outlook policy: http://www.howto-outlook.com/howto/policies.htm&lt;br /&gt;
* Folder with interesting policy settings on Outlook [http://theether.net/download/Microsoft/Office/2007/].&lt;br /&gt;
&lt;br /&gt;
== Unlocking ==&lt;br /&gt;
&lt;br /&gt;
===Main registry keys===&lt;br /&gt;
Apparently important registry keys are under:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook&lt;br /&gt;
Some tips [http://www.hotline-pc.org/outlook.htm here] (french)&lt;br /&gt;
&lt;br /&gt;
===IMAP settings===&lt;br /&gt;
&lt;br /&gt;
We can remove the admin barrier on account management:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup\ModifyAccounts&lt;br /&gt;
 =0&lt;br /&gt;
&lt;br /&gt;
Another way without modifying the Registry is to use the import feature:&lt;br /&gt;
&amp;lt;br&amp;gt;If e.g. Outlook Express client is also present on the Windows machine&lt;br /&gt;
* In Outlook Express:&lt;br /&gt;
** Wizard -&amp;gt; typed my IMAP&amp;amp;SMTP settings&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** File -&amp;gt; Import and Export... -&amp;gt; Import Internet Mail Account Settings -&amp;gt; Microsoft Outlook Express or Microsoft Windows Mail -&amp;gt; Wizard allowing to edit the imported settings :-)&lt;br /&gt;
** Then write a new mail -&amp;gt; Account (below Send button) -&amp;gt; select your new account -&amp;gt; Send test mail -&amp;gt; Prompted to choose the sent folder, ok -&amp;gt; you&#039;ve a multiple tabs config view of your new account, possibility to switch servers to TLS, changing name of the account, saying you need auth to talk to your SMTP etc etc&lt;br /&gt;
** If you need to tune IMAP settings later, go to registry and reset key (000000NN must be replaced with the number of your IMAP profile)&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676\000000NN\IMAP Sentitems&lt;br /&gt;
 = 0&lt;br /&gt;
&lt;br /&gt;
Note that I also tried importing from Eudora Light &amp;amp; Eudora but Outlook didn&#039;t see anything&lt;br /&gt;
&lt;br /&gt;
=== Cached Exchange Mode ===&lt;br /&gt;
The following keys were set in my configuration, preventing to change the settings related to &#039;&#039;Cached Exchange Mode&#039;&#039;. In particular the mode selection was disabled, ie. the options &#039;&#039;Download full items&#039;&#039;, &#039;&#039;Download headers and then full items&#039;&#039;, &#039;&#039;Download headers&#039;&#039; were all grayed out.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;reg&amp;quot;&amp;gt;&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Cached Mode]&lt;br /&gt;
&amp;quot;CachedExchangeMode&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;Enable&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoDrizzle&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoFullItems&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoHeaders&amp;quot;=dword:00000000&lt;br /&gt;
&amp;quot;NoManualOnlineSync&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;SyncPFFav&amp;quot;=dword:00000001&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
To unlock all settings, and eg. allow download full headers, simply delete values &#039;&#039;CachedExchangeMode&#039;&#039;, &#039;&#039;NoDrizzle&#039;&#039;, &#039;&#039;NoFullItems&#039;&#039;, &#039;&#039;NoHeaders&#039;&#039;, and &#039;&#039;NoManualOnlineSync&#039;&#039; (ie. all but &#039;&#039;Enable&#039;&#039; and &#039;&#039;SyncPFFav&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Changing JunkMail levels===&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Options\Mail\JunkMailProtection&lt;br /&gt;
 No Protection = 0xffffffff = 4294967295&lt;br /&gt;
 Low = 6&lt;br /&gt;
 High = 3&lt;br /&gt;
 Trusted Lists Only = 0x80000000 = 2147483648&lt;br /&gt;
To enable the JunkMail otions in the Options-&amp;gt;Preferences-&amp;gt;E-Mail-&amp;gt;Junk E-mail menu&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\DisableAntiSpam&lt;br /&gt;
 =0&lt;br /&gt;
&lt;br /&gt;
===All in one registry file===&lt;br /&gt;
You can also put all the above registry modifications in one single file [{{#file:Outlook.reg}} Outlook.reg]&lt;br /&gt;
&amp;lt;source lang=reg&amp;gt;&lt;br /&gt;
Windows Registry Editor Version 5.00&lt;br /&gt;
&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook]&lt;br /&gt;
&amp;quot;DisableAntiSpam&amp;quot;=dword:00000000&lt;br /&gt;
&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Cached Mode]&lt;br /&gt;
&amp;quot;NoFullItems&amp;quot;=-&lt;br /&gt;
&amp;quot;NoDrizzle&amp;quot;=-&lt;br /&gt;
&amp;quot;NoHeaders&amp;quot;=-&lt;br /&gt;
&amp;quot;CachedExchangeMode&amp;quot;=-&lt;br /&gt;
&amp;quot;NoManualOnlineSync&amp;quot;=-&lt;br /&gt;
&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Options\Mail]&lt;br /&gt;
&amp;quot;JunkMailProtection&amp;quot;=-&lt;br /&gt;
&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup]&lt;br /&gt;
&amp;quot;ModifyAccounts&amp;quot;=dword:00000000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and modify the registry at each startup with the following command:&lt;br /&gt;
 regedit /s Outlook.reg&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the hyphen after the registry value indicates a request to delete the value. See http://support.microsoft.com/kb/310516 for details.&lt;br /&gt;
&lt;br /&gt;
==Group Policy and other configuration hints==&lt;br /&gt;
&lt;br /&gt;
* [http://technet.microsoft.com/en-us/library/cc303396.aspx Configure Outlook security and protection features]&lt;br /&gt;
* [http://books.google.com/books?id=v8oZNEByTR0C&amp;amp;pg=PA232&amp;amp;lpg=PA232&amp;amp;dq=Outlook+policy+JunkMailProtection+registry&amp;amp;source=web&amp;amp;ots=NgPRrRu7ms&amp;amp;sig=0Fz7fiRm-hpc8GQTp9od3GtLLrM&amp;amp;hl=en&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;resnum=9&amp;amp;ct=result#PPA221,M1 Configuring Microsoft Outlook 2003]&lt;br /&gt;
&lt;br /&gt;
To use the Group Policy for Microsoft Outlook 2007 you may need to install the Outlook Group Policy template [http://www.yobi.be/files/outlk12.adm Outlk12.adm]&lt;br /&gt;
&lt;br /&gt;
# Copy the policy template Outlk12.adm into %WINDIR%\inf&lt;br /&gt;
# Open Group Policy Editor: Start-&amp;gt; Run-&amp;gt; gpedit.msc&lt;br /&gt;
# Add template:&lt;br /&gt;
## Select User Configuration&lt;br /&gt;
## Right-click on  Administrative Templates&lt;br /&gt;
## Select Add/Remove properties-&amp;gt; Click Add button&lt;br /&gt;
## Browse to %WINDIR%\inf and select Outlk12.adm&lt;br /&gt;
&lt;br /&gt;
==iCalendar==&lt;br /&gt;
Outlook does not handle correctly the iCal file (*.ics) with recurrent event.&lt;br /&gt;
&lt;br /&gt;
Problem: when opening (eg.: double-click on the attachment) an iCal file with multiple events, ie. multiple VEVENT sections, Outlook tries to add a complete calendar. Your are prompted with a dialog box with the following question: &#039;&#039;&#039;Add this Internet Calendar to Outlook&#039;&#039;&#039;. It is probably not what you want. Most probably you just need to add the multiple events in your existing calendar.&lt;br /&gt;
&lt;br /&gt;
The solution requires to save the iCal file on your hard drive and import it back using the import function.&lt;br /&gt;
&lt;br /&gt;
# Save file as...&lt;br /&gt;
# File -&amp;gt; Import and Export...&lt;br /&gt;
# Select &#039;&#039;Import and iCalendar (*.ics) or vCalendar (.vcs)&#039;&#039;&lt;br /&gt;
# Browse and select your saved iCal file, done.&lt;br /&gt;
&lt;br /&gt;
Solution source: https://events.sfu.ca/manual/en/iCalExporter.htm.&lt;br /&gt;
&lt;br /&gt;
==Moving PST location==&lt;br /&gt;
cf [http://azcarya.blogspot.com/2008/02/gmail-outlook-2007-and-imap.html this post]&lt;br /&gt;
&lt;br /&gt;
# Close Outlook.&lt;br /&gt;
# Open Control Panel -&amp;gt; Choose Mails -&amp;gt; Click on Data files.&lt;br /&gt;
# Select the Account name and check for the location of the PST file. Leave the window open.&lt;br /&gt;
# Open the folder containing the PST. Move the PST to the desired location.&lt;br /&gt;
# Do NOT rename the file - if you do Outlook creates a new file in the default location again.&lt;br /&gt;
# Switch to the Data Files window (as opened in Step 2) and double click on the PST file location.&lt;br /&gt;
# This displays an error window, Ignore the error, and point to the new location. Close the windows.&lt;br /&gt;
# Restart Outlook.&lt;br /&gt;
# Outlook may create a new PST in the default location again, delete it, in such a case.&lt;br /&gt;
&lt;br /&gt;
==Recovering PST password==&lt;br /&gt;
Password protection of PST is terribly wrong.&lt;br /&gt;
&lt;br /&gt;
Get [http://www.nirsoft.net/utils/pst_password.html PstPassword, a free Outlook PST Password Recovery], launch it and launch your PST, you&#039;ll get instantly a password, actuallt many passwords, and they will all work! How is it possible? Read [http://www.nirsoft.net/articles/pst_password_bug.html this].&lt;br /&gt;
&lt;br /&gt;
Note that McAfee detects the program as &amp;quot;Potentially Unwanted Program&amp;quot;, a &amp;quot;[http://vil.nai.com/vil/content/v_150020.htm Generic PUP.z]&amp;quot;:&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;McAfee(R) Avert™ recognizes that this program may have legitimate uses in contexts where an authorized administrator has knowingly installed this application&#039;&#039;&lt;br /&gt;
&amp;lt;br&amp;gt;But still no question, the program is simply erased by McAfee.&lt;br /&gt;
&amp;lt;br&amp;gt;One easy solution: open it under andLinux and run it with WINE :-)&lt;br /&gt;
&lt;br /&gt;
Apparently this can work both on &amp;quot;compressible encryption&amp;quot; and &amp;quot;high encryption&amp;quot; types of PST.&lt;br /&gt;
==Macro Send &amp;amp; Save==&lt;br /&gt;
Lotus Notes can prompt the sender to specify what folder a message should be saved in. In Outlook, you can set the storage folder on the Options dialog. This VBA code reproduces something closer to the Notes behavior by popping up the Select Folder dialog when the user sends the message. (see [http://www.outlookcode.com/d/code/setsavefolder.htm here] and [http://www.outlookcode.com/codedetail.aspx?id=456 there])&lt;br /&gt;
&amp;lt;br&amp;gt;&#039;&#039;UPDATE:&#039;&#039; Avoid treating appointments as it fails.&lt;br /&gt;
&amp;lt;source lang=vb&amp;gt;&lt;br /&gt;
Private Sub Application_ItemSend(ByVal Item As Object, _&lt;br /&gt;
    Cancel As Boolean)&lt;br /&gt;
  Dim objNS As NameSpace&lt;br /&gt;
  Dim objFolder As MAPIFolder&lt;br /&gt;
  Set objNS = Application.GetNamespace(&amp;quot;MAPI&amp;quot;)&lt;br /&gt;
  If TypeOf Item Is MailItem Then&lt;br /&gt;
    Set objFolder = objNS.PickFolder&lt;br /&gt;
    If TypeName(objFolder) &amp;lt;&amp;gt; &amp;quot;Nothing&amp;quot; Then&lt;br /&gt;
         Set Item.SaveSentMessageFolder = objFolder&lt;br /&gt;
    End If&lt;br /&gt;
  End If&lt;br /&gt;
  Set objFolder = Nothing&lt;br /&gt;
  Set objNS = Nothing&lt;br /&gt;
End Sub&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
To install it:&lt;br /&gt;
* Alt-F11 in Outlook&lt;br /&gt;
* Open Project1 -&amp;gt; Microsoft Office Outlook Objects -&amp;gt; ThisOutlookSession (double-click)&lt;br /&gt;
* copy/paste code&lt;br /&gt;
* close &amp;amp; save&lt;br /&gt;
Then allow unsigned macros:&lt;br /&gt;
* Tools -&amp;gt; Macro -&amp;gt; Security -&amp;gt; Macro Security -&amp;gt; Warning for all macros&lt;br /&gt;
You&#039;ll have annoying popup at startup but there is no way around&lt;br /&gt;
&lt;br /&gt;
==Interoperability between Exchange/Outlook &amp;amp; Linux==&lt;br /&gt;
&lt;br /&gt;
===PST to Maildir===&lt;br /&gt;
&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** New -&amp;gt; Outlook Data File... -&amp;gt; Outlook 97-2002 Personal Folders file&lt;br /&gt;
** Copy/Move mails to it&lt;br /&gt;
** Right-Click on it -&amp;gt; Close it (probably safer)&lt;br /&gt;
* In Linux:&lt;br /&gt;
** Convert to mbox using readpst, then to Maildir using mb2md&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
mkdir pst&lt;br /&gt;
readpst -r -o pst backup.pst&lt;br /&gt;
find pst -name mbox -size 0 -exec rm {} \;&lt;br /&gt;
find pst -mindepth 2 -type d -print0|xargs --null -I XXX mb2md -s &amp;quot;$(pwd)/XXX/mbox&amp;quot; -&lt;br /&gt;
find pst -mindepth 2 -name mbox -print0|xargs --null rm&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I tried the PST Import plugin v1.2 for Thunderbird but it failed finding any mail in the PST&lt;br /&gt;
===Openchange===&lt;br /&gt;
I tried the one from Debian Experimental (version  1.0~svn679-1)&lt;br /&gt;
 mapiprofile --address=A.B.C.D --username=name --password=passwd --domain=DOM --workstation=BLABLA --profile=test --create&lt;br /&gt;
-&amp;gt; segfault from libmapi0&lt;br /&gt;
&lt;br /&gt;
I tried to compile the libmapi0 from the SVN, no segfault anymore but still failed&lt;br /&gt;
===Evolution===&lt;br /&gt;
Apparently ther is an attempt to support MAPI in a development branch but it has too much recent dependencies for me to compile it...&lt;br /&gt;
 svn checkout http://svn.gnome.org/svn/evolution/branches/EXCHANGE_MAPI_BRANCH&lt;br /&gt;
&lt;br /&gt;
 svn diff http://svn.gnome.org/svn/evolution/trunk http://svn.gnome.org/svn/evolution/branches/EXCHANGE_MAPI_BRANCH&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=MiscCrypto&amp;diff=5073</id>
		<title>MiscCrypto</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=MiscCrypto&amp;diff=5073"/>
		<updated>2008-10-01T16:01:42Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* To unlock password-protected pdfs */ user pwd/owner pwd&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Under Windows==&lt;br /&gt;
===[http://www.cryptool.com/ CryptTool]===&lt;br /&gt;
* Demonstration and Reference Program for Cryptography + making AES executables&lt;br /&gt;
* freeware&lt;br /&gt;
===[http://axcrypt.sourceforge.net/ AxCrypt]===&lt;br /&gt;
* AES-128 File Encryption, Compression and double-click Edit/View for secure document storage on Windows 95/98/ME/NT/2K/XP, locally or remote.&lt;br /&gt;
* GPL&lt;br /&gt;
===[http://www.chilkatsoft.com/ChilkatSfx.asp Zip 2 Secure EXE]===&lt;br /&gt;
* AES-128/192/256 bits File Encryption, Create self-extracting EXE files from zip files&lt;br /&gt;
* freeware&lt;br /&gt;
==[[LoopCrypt]]==&lt;br /&gt;
==[[Encfs]]==&lt;br /&gt;
==[[TrueCrypt]]==&lt;br /&gt;
==[[LUKS]]==&lt;br /&gt;
&lt;br /&gt;
==Misc==&lt;br /&gt;
===To unlock password-protected pdfs===&lt;br /&gt;
* PDF documents may have up to 2 passwords:&lt;br /&gt;
** &#039;&#039;&#039;User password&#039;&#039;&#039;: protects read access to the document, and when no &#039;&#039;Owner password&#039;&#039; is specified, also protects permission settings.&lt;br /&gt;
** &#039;&#039;&#039;Owner password&#039;&#039;&#039;: protects full access to the document, and protects permission settings (printing, copying...)&lt;br /&gt;
&lt;br /&gt;
* Use &amp;lt;tt&amp;gt;pdftops&amp;lt;/tt&amp;gt; to remove password from a protected PDF. It works with either password, but when both passwords are set, it also works when only the &#039;&#039;user password&#039;&#039; is known (upon condition that permission &amp;lt;tt&amp;gt;allow Printing&amp;lt;/tt&amp;gt; is set).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get install gs-common xpdf-utils&lt;br /&gt;
pdftops -upw &amp;lt;password&amp;gt; &amp;lt;encrypted&amp;gt;.pdf &amp;lt;decrypted&amp;gt;.ps              # To generate a PostScript file (e.g. for further editing)&lt;br /&gt;
pdftops -upw &amp;lt;password&amp;gt; &amp;lt;encrypted&amp;gt;.pdf -|ps2pdf - &amp;lt;decrypted&amp;gt;.pdf  # To generate a new PDF&lt;br /&gt;
pdftops -opw &amp;lt;password&amp;gt; &amp;lt;encrypted&amp;gt;.pdf -|ps2pdf - &amp;lt;decrypted&amp;gt;.pdf  # When the Owner Password is known...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* An other solution is to use &#039;&#039;PDF Toolkit&#039;&#039; &amp;lt;tt&amp;gt;pdftk&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;apt-get install pdftk&amp;lt;/tt&amp;gt;). However unlike &#039;&#039;pdftops&#039;&#039; this method doesn&#039;t work when only &#039;&#039;user password&#039;&#039; is known but both passwords are set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;pdftk &amp;lt;encrypted&amp;gt;.pdf input_pw &amp;lt;password&amp;gt; output &amp;lt;decrypted&amp;gt;.pdf&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;pdftk&amp;lt;/tt&amp;gt; can also be used to generate protected documents, and specifying permissions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pdftk &amp;lt;unprotected&amp;gt;.pdf output &amp;lt;protected&amp;gt;.pdf allow Printing owner_pw &amp;lt;ownerpwd&amp;gt; user_pw &amp;lt;userpwd&amp;gt;    #Allow HQ printing&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===pwsafe===&lt;br /&gt;
To use &#039;secure ram&#039; (thereby locking the data in memory and preventing it being flushed to disk) you may like to run it setuid root:&lt;br /&gt;
 $ sudo dpkg-statoverride --update --add --force root root 4755 /usr/bin/pwsafe&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Outlook&amp;diff=4998</id>
		<title>Outlook</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Outlook&amp;diff=4998"/>
		<updated>2008-09-25T09:46:12Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Cached Mode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A page about Outlook on this wiki? Sounds weird isn&#039;t it?&lt;br /&gt;
&amp;lt;br&amp;gt;Well, blame my employer.&lt;br /&gt;
&lt;br /&gt;
We migrated from Lotus Notes, with crappy hacked outdated client so Outlook is still better but...&lt;br /&gt;
&amp;lt;br&amp;gt;At least under Lotus Notes it was possible to add an IMAP account (BTW Lotus Notes crashed quite often when talking IMAP...)&lt;br /&gt;
&amp;lt;br&amp;gt;Here: Tools-&amp;gt;Account Settings-&amp;gt;&#039;&#039;This feature has been disabled by your system administrator&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
* Microsoft Office 2007 Resource Kit (official documentation from Microsoft)&lt;br /&gt;
** [http://technet.microsoft.com/en-gb/library/cc178979.aspx Documentation page]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkId=85671 Security for the 2007 Office release]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkID=94264 Group Policy overview for the 2007 Office release]&lt;br /&gt;
** [http://go.microsoft.com/fwlink/?LinkId=78161 Administrative template (ADM,ADMX,...) files]&lt;br /&gt;
*** Use [http://www.7-zip.org/ 7-zip] to decompress this file without installing it. Don&#039;t miss the summary excel sheet inside.&lt;br /&gt;
* &#039;&#039;Configuring Microsoft Outlook 2003&#039;&#039;, By Sue Mosher, Robert Sparnaaij, Charlie Pulfer, David Hooker.&lt;br /&gt;
** Excellent book for administering Outlook 2003. Content can be browsed/searched on [http://books.google.com/books?id=v8oZNEByTR0C Google Books].&lt;br /&gt;
* Excellent 3rd party page on Outlook policy: http://www.howto-outlook.com/howto/policies.htm&lt;br /&gt;
* Folder with interesting policy settings on Outlook [http://theether.net/download/Microsoft/Office/2007/].&lt;br /&gt;
&lt;br /&gt;
==Main registry keys==&lt;br /&gt;
Apparently important registry keys are under:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook&lt;br /&gt;
Some tips [http://www.hotline-pc.org/outlook.htm here] (french)&lt;br /&gt;
&lt;br /&gt;
== Unlocking ==&lt;br /&gt;
&lt;br /&gt;
===Injecting IMAP settings===&lt;br /&gt;
&lt;br /&gt;
Outlook Express client was also present on the Windows machine so I launched it&lt;br /&gt;
* In Outlook Express:&lt;br /&gt;
** Wizard -&amp;gt; typed my IMAP&amp;amp;SMTP settings&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** File -&amp;gt; Import and Export... -&amp;gt; Import Internet Mail Account Settings -&amp;gt; Microsoft Outlook Express or Microsoft Windows Mail -&amp;gt; Wizard allowing to edit the imported settings :-)&lt;br /&gt;
** Then write a new mail -&amp;gt; Account (below Send button) -&amp;gt; select your new account -&amp;gt; Send test mail -&amp;gt; Prompted to choose the sent folder, ok -&amp;gt; you&#039;ve a multiple tabs config view of your new account, possibility to switch servers to TLS, changing name of the account, saying you need auth to talk to your SMTP etc etc&lt;br /&gt;
** If you need to tune IMAP settings later, go to registry and reset key (000000NN must be replaced with the number of your IMAP profile)&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676\000000NN\IMAP Sentitems&lt;br /&gt;
 = 0&lt;br /&gt;
&lt;br /&gt;
Previously I tried importing from Eudora Light &amp;amp; Eudora but Outlook didn&#039;t see anything&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UPDATE&#039;&#039;&#039; actually we can remove the admin barrier on account management:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup\ModifyAccounts&lt;br /&gt;
 =0&lt;br /&gt;
&lt;br /&gt;
=== Cached Exchange Mode ===&lt;br /&gt;
The following keys were set in my configuration, preventing to change the settings related to &#039;&#039;Cached Exchange Mode&#039;&#039;. In particular the mode selection was disabled, ie. the options &#039;&#039;Download full items&#039;&#039;, &#039;&#039;Download headers and then full items&#039;&#039;, &#039;&#039;Download headers&#039;&#039; were all grayed out.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;reg&amp;quot;&amp;gt;&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Cached Mode]&lt;br /&gt;
&amp;quot;CachedExchangeMode&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;Enable&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoDrizzle&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoFullItems&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoHeaders&amp;quot;=dword:00000000&lt;br /&gt;
&amp;quot;NoManualOnlineSync&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;SyncPFFav&amp;quot;=dword:00000001&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
To unlock all settings, and eg. allow download full headers, simply delete values &#039;&#039;CachedExchangeMode&#039;&#039;, &#039;&#039;NoDrizzle&#039;&#039;, &#039;&#039;NoFullItems&#039;&#039;, &#039;&#039;NoHeaders&#039;&#039;, and &#039;&#039;NoManualOnlineSync&#039;&#039; (ie. all but &#039;&#039;Enable&#039;&#039; and &#039;&#039;SyncPFFav&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Moving PST location==&lt;br /&gt;
cf [http://azcarya.blogspot.com/2008/02/gmail-outlook-2007-and-imap.html this post]&lt;br /&gt;
&lt;br /&gt;
# Close Outlook.&lt;br /&gt;
# Open Control Panel -&amp;gt; Choose Mails -&amp;gt; Click on Data files.&lt;br /&gt;
# Select the Account name and check for the location of the PST file. Leave the window open.&lt;br /&gt;
# Open the folder containing the PST. Move the PST to the desired location.&lt;br /&gt;
# Do NOT rename the file - if you do Outlook creates a new file in the default location again.&lt;br /&gt;
# Switch to the Data Files window (as opened in Step 2) and double click on the PST file location.&lt;br /&gt;
# This displays an error window, Ignore the error, and point to the new location. Close the windows.&lt;br /&gt;
# Restart Outlook.&lt;br /&gt;
# Outlook may create a new PST in the default location again, delete it, in such a case.&lt;br /&gt;
&lt;br /&gt;
==PST to Maildir==&lt;br /&gt;
&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** New -&amp;gt; Outlook Data File... -&amp;gt; Outlook 97-2002 Personal Folders file&lt;br /&gt;
** Copy/Move mails to it&lt;br /&gt;
** Right-Click on it -&amp;gt; Close it (probably safer)&lt;br /&gt;
* In Linux:&lt;br /&gt;
** Convert to mbox using readpst, then to Maildir using mb2md&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
mkdir pst&lt;br /&gt;
readpst -r -o pst backup.pst&lt;br /&gt;
find pst -name mbox -size 0 -exec rm {} \;&lt;br /&gt;
find pst -mindepth 2 -type d -print0|xargs --null -I XXX mb2md -s &amp;quot;$(pwd)/XXX/mbox&amp;quot; -&lt;br /&gt;
find pst -mindepth 2 -name mbox -print0|xargs --null rm&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I tried the PST Import plugin v1.2 for Thunderbird but it failed finding any mail in the PST&lt;br /&gt;
==Openchange==&lt;br /&gt;
I tried the one from Debian Experimental (version  1.0~svn679-1)&lt;br /&gt;
 mapiprofile --address=A.B.C.D --username=name --password=passwd --domain=DOM --workstation=BLABLA --profile=test --create&lt;br /&gt;
-&amp;gt; segfault from libmapi0&lt;br /&gt;
&lt;br /&gt;
I tried to compile the libmapi0 from the SVN, no segfault anymore but still failed&lt;br /&gt;
==Evolution==&lt;br /&gt;
Apparently ther is an attempt to support MAPI in a development branch but it has too much recent dependencies for me to compile it...&lt;br /&gt;
 svn checkout http://svn.gnome.org/svn/evolution/branches/EXCHANGE_MAPI_BRANCH&lt;br /&gt;
&lt;br /&gt;
 svn diff http://svn.gnome.org/svn/evolution/trunk http://svn.gnome.org/svn/evolution/branches/EXCHANGE_MAPI_BRANCH&lt;br /&gt;
&lt;br /&gt;
==Changing JunkMail levels via registry==&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Options\Mail\JunkMailProtection&lt;br /&gt;
 No Protection = 0xffffffff = 4294967295&lt;br /&gt;
 Low = 6&lt;br /&gt;
 High = 3&lt;br /&gt;
 Trusted Lists Only = 0x80000000 = 2147483648&lt;br /&gt;
To enable the JunkMail otions in the Options-&amp;gt;Preferences-&amp;gt;E-Mail-&amp;gt;Junk E-mail menu&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\DisableAntiSpam&lt;br /&gt;
 =0&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Outlook&amp;diff=4997</id>
		<title>Outlook</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Outlook&amp;diff=4997"/>
		<updated>2008-09-25T09:34:03Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* Unlocking */ Cached mode - allow full header download&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A page about Outlook on this wiki? Sounds weird isn&#039;t it?&lt;br /&gt;
&amp;lt;br&amp;gt;Well, blame my employer.&lt;br /&gt;
&lt;br /&gt;
We migrated from Lotus Notes, with crappy hacked outdated client so Outlook is still better but...&lt;br /&gt;
&amp;lt;br&amp;gt;At least under Lotus Notes it was possible to add an IMAP account (BTW Lotus Notes crashed quite often when talking IMAP...)&lt;br /&gt;
&amp;lt;br&amp;gt;Here: Tools-&amp;gt;Account Settings-&amp;gt;&#039;&#039;This feature has been disabled by your system administrator&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
* Microsoft Office 2007 Resource Kit (official documentation from Microsoft)&lt;br /&gt;
** [http://technet.microsoft.com/en-gb/library/cc178979.aspx Documentation page]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkId=85671 Security for the 2007 Office release]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkID=94264 Group Policy overview for the 2007 Office release]&lt;br /&gt;
** [http://go.microsoft.com/fwlink/?LinkId=78161 Administrative template (ADM,ADMX,...) files]&lt;br /&gt;
*** Use [http://www.7-zip.org/ 7-zip] to decompress this file without installing it. Don&#039;t miss the summary excel sheet inside.&lt;br /&gt;
* &#039;&#039;Configuring Microsoft Outlook 2003&#039;&#039;, By Sue Mosher, Robert Sparnaaij, Charlie Pulfer, David Hooker.&lt;br /&gt;
** Excellent book for administering Outlook 2003. Content can be browsed/searched on [http://books.google.com/books?id=v8oZNEByTR0C Google Books].&lt;br /&gt;
* Excellent 3rd party page on Outlook policy: http://www.howto-outlook.com/howto/policies.htm&lt;br /&gt;
* Folder with interesting policy settings on Outlook [http://theether.net/download/Microsoft/Office/2007/].&lt;br /&gt;
&lt;br /&gt;
==Main registry keys==&lt;br /&gt;
Apparently important registry keys are under:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook&lt;br /&gt;
Some tips [http://www.hotline-pc.org/outlook.htm here] (french)&lt;br /&gt;
&lt;br /&gt;
== Unlocking ==&lt;br /&gt;
&lt;br /&gt;
===Injecting IMAP settings===&lt;br /&gt;
&lt;br /&gt;
Outlook Express client was also present on the Windows machine so I launched it&lt;br /&gt;
* In Outlook Express:&lt;br /&gt;
** Wizard -&amp;gt; typed my IMAP&amp;amp;SMTP settings&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** File -&amp;gt; Import and Export... -&amp;gt; Import Internet Mail Account Settings -&amp;gt; Microsoft Outlook Express or Microsoft Windows Mail -&amp;gt; Wizard allowing to edit the imported settings :-)&lt;br /&gt;
** Then write a new mail -&amp;gt; Account (below Send button) -&amp;gt; select your new account -&amp;gt; Send test mail -&amp;gt; Prompted to choose the sent folder, ok -&amp;gt; you&#039;ve a multiple tabs config view of your new account, possibility to switch servers to TLS, changing name of the account, saying you need auth to talk to your SMTP etc etc&lt;br /&gt;
** If you need to tune IMAP settings later, go to registry and reset key (000000NN must be replaced with the number of your IMAP profile)&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676\000000NN\IMAP Sentitems&lt;br /&gt;
 = 0&lt;br /&gt;
&lt;br /&gt;
Previously I tried importing from Eudora Light &amp;amp; Eudora but Outlook didn&#039;t see anything&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UPDATE&#039;&#039;&#039; actually we can remove the admin barrier on account management:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup\ModifyAccounts&lt;br /&gt;
 =0&lt;br /&gt;
&lt;br /&gt;
=== Cached Mode ===&lt;br /&gt;
The following keys were set in my configuration, preventing to change the settings related to &#039;&#039;Cached Mode&#039;&#039; (in particular the selection between &#039;&#039;Download headers&#039;&#039;, &#039;&#039;Download headers and then full items&#039;&#039;, etc.):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;reg&amp;quot;&amp;gt;&lt;br /&gt;
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Cached Mode]&lt;br /&gt;
&amp;quot;CachedExchangeMode&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;Enable&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoDrizzle&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoFullItems&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;NoHeaders&amp;quot;=dword:00000000&lt;br /&gt;
&amp;quot;NoManualOnlineSync&amp;quot;=dword:00000001&lt;br /&gt;
&amp;quot;SyncPFFav&amp;quot;=dword:00000001&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
To unlock all settings, simply delete values &#039;&#039;CachedExchangeMode&#039;&#039;, &#039;&#039;NoDrizzle&#039;&#039;, &#039;&#039;NoFullItems&#039;&#039;, &#039;&#039;NoHeaders&#039;&#039;, and &#039;&#039;NoManualOnlineSync&#039;&#039; (ie. all but &#039;&#039;Enable&#039;&#039; and &#039;&#039;SyncPFFav&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
==Moving PST location==&lt;br /&gt;
cf [http://azcarya.blogspot.com/2008/02/gmail-outlook-2007-and-imap.html this post]&lt;br /&gt;
&lt;br /&gt;
# Close Outlook.&lt;br /&gt;
# Open Control Panel -&amp;gt; Choose Mails -&amp;gt; Click on Data files.&lt;br /&gt;
# Select the Account name and check for the location of the PST file. Leave the window open.&lt;br /&gt;
# Open the folder containing the PST. Move the PST to the desired location.&lt;br /&gt;
# Do NOT rename the file - if you do Outlook creates a new file in the default location again.&lt;br /&gt;
# Switch to the Data Files window (as opened in Step 2) and double click on the PST file location.&lt;br /&gt;
# This displays an error window, Ignore the error, and point to the new location. Close the windows.&lt;br /&gt;
# Restart Outlook.&lt;br /&gt;
# Outlook may create a new PST in the default location again, delete it, in such a case.&lt;br /&gt;
&lt;br /&gt;
==PST to Maildir==&lt;br /&gt;
&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** New -&amp;gt; Outlook Data File... -&amp;gt; Outlook 97-2002 Personal Folders file&lt;br /&gt;
** Copy/Move mails to it&lt;br /&gt;
** Right-Click on it -&amp;gt; Close it (probably safer)&lt;br /&gt;
* In Linux:&lt;br /&gt;
** Convert to mbox using readpst, then to Maildir using mb2md&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
mkdir pst&lt;br /&gt;
readpst -r -o pst backup.pst&lt;br /&gt;
find pst -name mbox -size 0 -exec rm {} \;&lt;br /&gt;
find pst -mindepth 2 -type d -print0|xargs --null -I XXX mb2md -s &amp;quot;$(pwd)/XXX/mbox&amp;quot; -&lt;br /&gt;
find pst -mindepth 2 -name mbox -print0|xargs --null rm&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I tried the PST Import plugin v1.2 for Thunderbird but it failed finding any mail in the PST&lt;br /&gt;
==Openchange==&lt;br /&gt;
I tried the one from Debian Experimental (version  1.0~svn679-1)&lt;br /&gt;
 mapiprofile --address=A.B.C.D --username=name --password=passwd --domain=DOM --workstation=BLABLA --profile=test --create&lt;br /&gt;
-&amp;gt; segfault from libmapi0&lt;br /&gt;
&lt;br /&gt;
I tried to compile the libmapi0 from the SVN, no segfault anymore but still failed&lt;br /&gt;
==Evolution==&lt;br /&gt;
Apparently ther is an attempt to support MAPI in a development branch but it has too much recent dependencies for me to compile it...&lt;br /&gt;
 svn checkout http://svn.gnome.org/svn/evolution/branches/EXCHANGE_MAPI_BRANCH&lt;br /&gt;
&lt;br /&gt;
 svn diff http://svn.gnome.org/svn/evolution/trunk http://svn.gnome.org/svn/evolution/branches/EXCHANGE_MAPI_BRANCH&lt;br /&gt;
&lt;br /&gt;
==Changing JunkMail levels via registry==&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Options\Mail\JunkMailProtection&lt;br /&gt;
 No Protection = 0xffffffff = 4294967295&lt;br /&gt;
 Low = 6&lt;br /&gt;
 High = 3&lt;br /&gt;
 Trusted Lists Only = 0x80000000 = 2147483648&lt;br /&gt;
To enable the JunkMail otions in the Options-&amp;gt;Preferences-&amp;gt;E-Mail-&amp;gt;Junk E-mail menu&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\DisableAntiSpam&lt;br /&gt;
 =0&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
	<entry>
		<id>https://wiki.yobi.be/index.php?title=Outlook&amp;diff=4987</id>
		<title>Outlook</title>
		<link rel="alternate" type="text/html" href="https://wiki.yobi.be/index.php?title=Outlook&amp;diff=4987"/>
		<updated>2008-09-23T20:23:31Z</updated>

		<summary type="html">&lt;p&gt;Fuujuhi: /* References */ Some interesting links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A page about Outlook on this wiki? Sounds weird isn&#039;t it?&lt;br /&gt;
&amp;lt;br&amp;gt;Well, blame my employer.&lt;br /&gt;
&lt;br /&gt;
We migrated from Lotus Notes, with crappy hacked outdated client so Outlook is still better but...&lt;br /&gt;
&amp;lt;br&amp;gt;At least under Lotus Notes it was possible to add an IMAP account (BTW Lotus Notes crashed quite often when talking IMAP...)&lt;br /&gt;
&amp;lt;br&amp;gt;Here: Tools-&amp;gt;Account Settings-&amp;gt;&#039;&#039;This feature has been disabled by your system administrator&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
* Microsoft Office 2007 Resource Kit (official documentation from Microsoft)&lt;br /&gt;
** [http://technet.microsoft.com/en-gb/library/cc178979.aspx Documentation page]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkId=85671 Security for the 2007 Office release]&lt;br /&gt;
*** [http://go.microsoft.com/fwlink/?LinkID=94264 Group Policy overview for the 2007 Office release]&lt;br /&gt;
** [http://go.microsoft.com/fwlink/?LinkId=78161 Administrative template (ADM,ADMX,...) files]&lt;br /&gt;
*** Use [http://www.7-zip.org/ 7-zip] to decompress this file without installing it. Don&#039;t miss the summary excel sheet inside.&lt;br /&gt;
* &#039;&#039;Configuring Microsoft Outlook 2003&#039;&#039;, By Sue Mosher, Robert Sparnaaij, Charlie Pulfer, David Hooker.&lt;br /&gt;
** Excellent book for administering Outlook 2003. Content can be browsed/searched on [http://books.google.com/books?id=v8oZNEByTR0C Google Books].&lt;br /&gt;
* Excellent 3rd party page on Outlook policy: http://www.howto-outlook.com/howto/policies.htm&lt;br /&gt;
* Folder with interesting policy settings on Outlook [http://theether.net/download/Microsoft/Office/2007/].&lt;br /&gt;
&lt;br /&gt;
==Main registry keys==&lt;br /&gt;
Apparently important registry keys are under:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook&lt;br /&gt;
Some tips [http://www.hotline-pc.org/outlook.htm here] (french)&lt;br /&gt;
&lt;br /&gt;
==Injecting IMAP settings==&lt;br /&gt;
&lt;br /&gt;
Outlook Express client was also present on the Windows machine so I launched it&lt;br /&gt;
* In Outlook Express:&lt;br /&gt;
** Wizard -&amp;gt; typed my IMAP&amp;amp;SMTP settings&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** File -&amp;gt; Import and Export... -&amp;gt; Import Internet Mail Account Settings -&amp;gt; Microsoft Outlook Express or Microsoft Windows Mail -&amp;gt; Wizard allowing to edit the imported settings :-)&lt;br /&gt;
** Then write a new mail -&amp;gt; Account (below Send button) -&amp;gt; select your new account -&amp;gt; Send test mail -&amp;gt; Prompted to choose the sent folder, ok -&amp;gt; you&#039;ve a multiple tabs config view of your new account, possibility to switch servers to TLS, changing name of the account, saying you need auth to talk to your SMTP etc etc&lt;br /&gt;
** If you need to tune IMAP settings later, go to registry and reset key (000000NN must be replaced with the number of your IMAP profile)&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676\000000NN\IMAP Sentitems&lt;br /&gt;
 = 0&lt;br /&gt;
&lt;br /&gt;
Previously I tried importing from Eudora Light &amp;amp; Eudora but Outlook didn&#039;t see anything&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;UPDATE&#039;&#039;&#039; actually we can remove the admin barrier on account management:&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup\ModifyAccounts&lt;br /&gt;
 =0&lt;br /&gt;
==Moving PST location==&lt;br /&gt;
cf [http://azcarya.blogspot.com/2008/02/gmail-outlook-2007-and-imap.html this post]&lt;br /&gt;
&lt;br /&gt;
# Close Outlook.&lt;br /&gt;
# Open Control Panel -&amp;gt; Choose Mails -&amp;gt; Click on Data files.&lt;br /&gt;
# Select the Account name and check for the location of the PST file. Leave the window open.&lt;br /&gt;
# Open the folder containing the PST. Move the PST to the desired location.&lt;br /&gt;
# Do NOT rename the file - if you do Outlook creates a new file in the default location again.&lt;br /&gt;
# Switch to the Data Files window (as opened in Step 2) and double click on the PST file location.&lt;br /&gt;
# This displays an error window, Ignore the error, and point to the new location. Close the windows.&lt;br /&gt;
# Restart Outlook.&lt;br /&gt;
# Outlook may create a new PST in the default location again, delete it, in such a case.&lt;br /&gt;
&lt;br /&gt;
==PST to Maildir==&lt;br /&gt;
&lt;br /&gt;
* In Outlook:&lt;br /&gt;
** New -&amp;gt; Outlook Data File... -&amp;gt; Outlook 97-2002 Personal Folders file&lt;br /&gt;
** Copy/Move mails to it&lt;br /&gt;
** Right-Click on it -&amp;gt; Close it (probably safer)&lt;br /&gt;
* In Linux:&lt;br /&gt;
** Convert to mbox using readpst, then to Maildir using mb2md&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
mkdir pst&lt;br /&gt;
readpst -r -o pst backup.pst&lt;br /&gt;
find pst -name mbox -size 0 -exec rm {} \;&lt;br /&gt;
find pst -mindepth 2 -type d -print0|xargs --null -I XXX mb2md -s &amp;quot;$(pwd)/XXX/mbox&amp;quot; -&lt;br /&gt;
find pst -mindepth 2 -name mbox -print0|xargs --null rm&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I tried the PST Import plugin v1.2 for Thunderbird but it failed finding any mail in the PST&lt;br /&gt;
==Openchange==&lt;br /&gt;
I tried the one from Debian Experimental (version  1.0~svn679-1)&lt;br /&gt;
 mapiprofile --address=A.B.C.D --username=name --password=passwd --domain=DOM --workstation=BLABLA --profile=test --create&lt;br /&gt;
-&amp;gt; segfault from libmapi0&lt;br /&gt;
&lt;br /&gt;
I tried to compile the libmapi0 from the SVN, no segfault anymore but still failed&lt;br /&gt;
&lt;br /&gt;
==Changing JunkMail levels via registry==&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Options\Mail\JunkMailProtection&lt;br /&gt;
 No Protection = 0xffffffff = 4294967295&lt;br /&gt;
 Low = 6&lt;br /&gt;
 High = 3&lt;br /&gt;
 Trusted Lists Only = 0x80000000 = 2147483648&lt;br /&gt;
To enable the JunkMail otions in the Options-&amp;gt;Preferences-&amp;gt;E-Mail-&amp;gt;Junk E-mail menu&lt;br /&gt;
 HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\DisableAntiSpam&lt;br /&gt;
 =0&lt;/div&gt;</summary>
		<author><name>Fuujuhi</name></author>
	</entry>
</feed>