| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | """Generic FAQ Wizard.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is a CGI program that maintains a user-editable FAQ.  It uses RCS | 
					
						
							|  |  |  | to keep track of changes to individual FAQ entries.  It is fully | 
					
						
							|  |  |  | configurable; everything you might want to change when using this | 
					
						
							|  |  |  | program to maintain some other FAQ than the Python FAQ is contained in | 
					
						
							|  |  |  | the configuration module, faqconf.py. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note that this is not an executable script; it's an importable module. | 
					
						
							| 
									
										
										
										
											1997-08-28 02:38:01 +00:00
										 |  |  | The actual script to place in cgi-bin is faqw.py. | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  | import sys, time, os, stat, re, cgi, faqconf | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  | from faqconf import *                   # This imports all uppercase names | 
					
						
							| 
									
										
										
										
											1997-05-26 19:46:56 +00:00
										 |  |  | now = time.time() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FileError: | 
					
						
							|  |  |  |     def __init__(self, file): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.file = file | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class InvalidFile(FileError): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | class NoSuchSection(FileError): | 
					
						
							|  |  |  |     def __init__(self, section): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         FileError.__init__(self, NEWFILENAME %(section, 1)) | 
					
						
							|  |  |  |         self.section = section | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | class NoSuchFile(FileError): | 
					
						
							|  |  |  |     def __init__(self, file, why=None): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         FileError.__init__(self, file) | 
					
						
							|  |  |  |         self.why = why | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | def escape(s): | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     s = s.replace('&', '&') | 
					
						
							|  |  |  |     s = s.replace('<', '<') | 
					
						
							|  |  |  |     s = s.replace('>', '>') | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     return s | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | def escapeq(s): | 
					
						
							|  |  |  |     s = escape(s) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     s = s.replace('"', '"') | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     return s | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | def _interpolate(format, args, kw): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         quote = kw['_quote'] | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     except KeyError: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         quote = 1 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     d = (kw,) + args + (faqconf.__dict__,) | 
					
						
							|  |  |  |     m = MagicDict(d, quote) | 
					
						
							|  |  |  |     return format % m | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def interpolate(format, *args, **kw): | 
					
						
							|  |  |  |     return _interpolate(format, args, kw) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | def emit(format, *args, **kw): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         f = kw['_file'] | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     except KeyError: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         f = sys.stdout | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     f.write(_interpolate(format, args, kw)) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | translate_prog = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-12-09 16:04:46 +00:00
										 |  |  | def translate(text, pre=0): | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     global translate_prog | 
					
						
							|  |  |  |     if not translate_prog: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         translate_prog = prog = re.compile( | 
					
						
							|  |  |  |             r'\b(http|ftp|https)://\S+(\b|/)|\b[-.\w]+@[-.\w]+') | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         prog = translate_prog | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     i = 0 | 
					
						
							|  |  |  |     list = [] | 
					
						
							|  |  |  |     while 1: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         m = prog.search(text, i) | 
					
						
							|  |  |  |         if not m: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         j = m.start() | 
					
						
							|  |  |  |         list.append(escape(text[i:j])) | 
					
						
							|  |  |  |         i = j | 
					
						
							|  |  |  |         url = m.group(0) | 
					
						
							|  |  |  |         while url[-1] in '();:,.?\'"<>': | 
					
						
							|  |  |  |             url = url[:-1] | 
					
						
							|  |  |  |         i = i + len(url) | 
					
						
							|  |  |  |         url = escape(url) | 
					
						
							|  |  |  |         if not pre or (pre and PROCESS_PREFORMAT): | 
					
						
							|  |  |  |             if ':' in url: | 
					
						
							|  |  |  |                 repl = '<A HREF="%s">%s</A>' % (url, url) | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											1998-07-07 22:39:21 +00:00
										 |  |  |                 repl = '<A HREF="mailto:%s">%s</A>' % (url, url) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             repl = url | 
					
						
							|  |  |  |         list.append(repl) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     j = len(text) | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     list.append(escape(text[i:j])) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     return ''.join(list) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def emphasize(line): | 
					
						
							| 
									
										
										
										
											1997-12-21 07:05:32 +00:00
										 |  |  |     return re.sub(r'\*([a-zA-Z]+)\*', r'<I>\1</I>', line) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 19:10:37 +00:00
										 |  |  | revparse_prog = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def revparse(rev): | 
					
						
							|  |  |  |     global revparse_prog | 
					
						
							|  |  |  |     if not revparse_prog: | 
					
						
							| 
									
										
										
										
											1998-05-22 19:43:21 +00:00
										 |  |  |         revparse_prog = re.compile(r'^(\d{1,3})\.(\d{1,4})$') | 
					
						
							| 
									
										
										
										
											1997-12-21 07:05:32 +00:00
										 |  |  |     m = revparse_prog.match(rev) | 
					
						
							|  |  |  |     if not m: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     [major, minor] = map(int, m.group(1, 2)) | 
					
						
							| 
									
										
										
										
											1997-05-26 19:10:37 +00:00
										 |  |  |     return major, minor | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-31 00:58:00 +00:00
										 |  |  | logon = 0 | 
					
						
							|  |  |  | def log(text): | 
					
						
							|  |  |  |     if logon: | 
					
						
							|  |  |  |         logfile = open("logfile", "a") | 
					
						
							|  |  |  |         logfile.write(text + "\n") | 
					
						
							|  |  |  |         logfile.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | def load_cookies(): | 
					
						
							|  |  |  |     if not os.environ.has_key('HTTP_COOKIE'): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         return {} | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     raw = os.environ['HTTP_COOKIE'] | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     words = [s.strip() for s in raw.split(';')] | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     cookies = {} | 
					
						
							|  |  |  |     for word in words: | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         i = word.find('=') | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if i >= 0: | 
					
						
							|  |  |  |             key, value = word[:i], word[i+1:] | 
					
						
							|  |  |  |             cookies[key] = value | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     return cookies | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def load_my_cookie(): | 
					
						
							|  |  |  |     cookies = load_cookies() | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         value = cookies[COOKIE_NAME] | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     except KeyError: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         return {} | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     import urllib | 
					
						
							|  |  |  |     value = urllib.unquote(value) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     words = value.split('/') | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     while len(words) < 3: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         words.append('') | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |     author = '/'.join(words[:-2]) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     email = words[-2] | 
					
						
							|  |  |  |     password = words[-1] | 
					
						
							|  |  |  |     return {'author': author, | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             'email': email, | 
					
						
							|  |  |  |             'password': password} | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | def send_my_cookie(ui): | 
					
						
							|  |  |  |     name = COOKIE_NAME | 
					
						
							|  |  |  |     value = "%s/%s/%s" % (ui.author, ui.email, ui.password) | 
					
						
							|  |  |  |     import urllib | 
					
						
							|  |  |  |     value = urllib.quote(value) | 
					
						
							|  |  |  |     then = now + COOKIE_LIFETIME | 
					
						
							|  |  |  |     gmt = time.gmtime(then) | 
					
						
							| 
									
										
										
										
											1998-09-04 21:19:55 +00:00
										 |  |  |     path = os.environ.get('SCRIPT_NAME', '/cgi-bin/') | 
					
						
							|  |  |  |     print "Set-Cookie: %s=%s; path=%s;" % (name, value, path), | 
					
						
							| 
									
										
										
										
											1998-02-02 03:19:06 +00:00
										 |  |  |     print time.strftime("expires=%a, %d-%b-%y %X GMT", gmt) | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class MagicDict: | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     def __init__(self, d, quote): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.__d = d | 
					
						
							|  |  |  |         self.__quote = quote | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, key): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         for d in self.__d: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 value = d[key] | 
					
						
							|  |  |  |                 if value: | 
					
						
							|  |  |  |                     value = str(value) | 
					
						
							|  |  |  |                     if self.__quote: | 
					
						
							|  |  |  |                         value = escapeq(value) | 
					
						
							|  |  |  |                     return value | 
					
						
							|  |  |  |             except KeyError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |         return '' | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class UserInput: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.__form = cgi.FieldStorage() | 
					
						
							| 
									
										
										
										
											2000-03-31 00:58:00 +00:00
										 |  |  |         #log("\n\nbody: " + self.body) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __getattr__(self, name): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if name[0] == '_': | 
					
						
							|  |  |  |             raise AttributeError | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             value = self.__form[name].value | 
					
						
							|  |  |  |         except (TypeError, KeyError): | 
					
						
							|  |  |  |             value = '' | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |             value = value.strip() | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         setattr(self, name, value) | 
					
						
							|  |  |  |         return value | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __getitem__(self, key): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         return getattr(self, key) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | class FaqEntry: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, fp, file, sec_num): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.file = file | 
					
						
							|  |  |  |         self.sec, self.num = sec_num | 
					
						
							|  |  |  |         if fp: | 
					
						
							|  |  |  |             import rfc822 | 
					
						
							|  |  |  |             self.__headers = rfc822.Message(fp) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |             self.body = fp.read().strip() | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             self.__headers = {'title': "%d.%d. " % sec_num} | 
					
						
							|  |  |  |             self.body = '' | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __getattr__(self, name): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if name[0] == '_': | 
					
						
							|  |  |  |             raise AttributeError | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         key = '-'.join(name.split('_')) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             value = self.__headers[key] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             value = '' | 
					
						
							|  |  |  |         setattr(self, name, value) | 
					
						
							|  |  |  |         return value | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     def __getitem__(self, key): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         return getattr(self, key) | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def load_version(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         command = interpolate(SH_RLOG_H, self) | 
					
						
							|  |  |  |         p = os.popen(command) | 
					
						
							|  |  |  |         version = '' | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             line = p.readline() | 
					
						
							|  |  |  |             if not line: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             if line[:5] == 'head:': | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |                 version = line[5:].strip() | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         p.close() | 
					
						
							|  |  |  |         self.version = version | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 19:46:56 +00:00
										 |  |  |     def getmtime(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if not self.last_changed_date: | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return os.stat(self.file)[stat.ST_MTIME] | 
					
						
							|  |  |  |         except os.error: | 
					
						
							|  |  |  |             return 0 | 
					
						
							| 
									
										
										
										
											1997-05-26 19:46:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def emit_marks(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         mtime = self.getmtime() | 
					
						
							|  |  |  |         if mtime >= now - DT_VERY_RECENT: | 
					
						
							|  |  |  |             emit(MARK_VERY_RECENT, self) | 
					
						
							|  |  |  |         elif mtime >= now - DT_RECENT: | 
					
						
							|  |  |  |             emit(MARK_RECENT, self) | 
					
						
							| 
									
										
										
										
											1997-05-26 19:46:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     def show(self, edit=1): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         emit(ENTRY_HEADER1, self) | 
					
						
							|  |  |  |         self.emit_marks() | 
					
						
							|  |  |  |         emit(ENTRY_HEADER2, self) | 
					
						
							|  |  |  |         pre = 0 | 
					
						
							|  |  |  |         raw = 0 | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         for line in self.body.split('\n'): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             # Allow the user to insert raw html into a FAQ answer | 
					
						
							|  |  |  |             # (Skip Montanaro, with changes by Guido) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |             tag = line.rstrip().lower() | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             if tag == '<html>': | 
					
						
							|  |  |  |                 raw = 1 | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if tag == '</html>': | 
					
						
							|  |  |  |                 raw = 0 | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if raw: | 
					
						
							|  |  |  |                 print line | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |             if not line.strip(): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |                 if pre: | 
					
						
							|  |  |  |                     print '</PRE>' | 
					
						
							|  |  |  |                     pre = 0 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     print '<P>' | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |                 if not line[0].isspace(): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |                     if pre: | 
					
						
							|  |  |  |                         print '</PRE>' | 
					
						
							|  |  |  |                         pre = 0 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     if not pre: | 
					
						
							|  |  |  |                         print '<PRE>' | 
					
						
							|  |  |  |                         pre = 1 | 
					
						
							|  |  |  |                 if '/' in line or '@' in line: | 
					
						
							|  |  |  |                     line = translate(line, pre) | 
					
						
							|  |  |  |                 elif '<' in line or '&' in line: | 
					
						
							|  |  |  |                     line = escape(line) | 
					
						
							|  |  |  |                 if not pre and '*' in line: | 
					
						
							|  |  |  |                     line = emphasize(line) | 
					
						
							|  |  |  |                 print line | 
					
						
							|  |  |  |         if pre: | 
					
						
							|  |  |  |             print '</PRE>' | 
					
						
							|  |  |  |             pre = 0 | 
					
						
							|  |  |  |         if edit: | 
					
						
							|  |  |  |             print '<P>' | 
					
						
							|  |  |  |             emit(ENTRY_FOOTER, self) | 
					
						
							|  |  |  |             if self.last_changed_date: | 
					
						
							|  |  |  |                 emit(ENTRY_LOGINFO, self) | 
					
						
							|  |  |  |         print '<P>' | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FaqDir: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     entryclass = FaqEntry | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-12-21 07:05:32 +00:00
										 |  |  |     __okprog = re.compile(OKFILENAME) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, dir=os.curdir): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.__dir = dir | 
					
						
							|  |  |  |         self.__files = None | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __fill(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if self.__files is not None: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.__files = files = [] | 
					
						
							|  |  |  |         okprog = self.__okprog | 
					
						
							|  |  |  |         for file in os.listdir(self.__dir): | 
					
						
							|  |  |  |             if self.__okprog.match(file): | 
					
						
							|  |  |  |                 files.append(file) | 
					
						
							|  |  |  |         files.sort() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def good(self, file): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         return self.__okprog.match(file) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def parse(self, file): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         m = self.good(file) | 
					
						
							|  |  |  |         if not m: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         sec, num = m.group(1, 2) | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         return int(sec), int(num) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def list(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         # XXX Caller shouldn't modify result | 
					
						
							|  |  |  |         self.__fill() | 
					
						
							|  |  |  |         return self.__files | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def open(self, file): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         sec_num = self.parse(file) | 
					
						
							|  |  |  |         if not sec_num: | 
					
						
							|  |  |  |             raise InvalidFile(file) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             fp = open(file) | 
					
						
							|  |  |  |         except IOError, msg: | 
					
						
							|  |  |  |             raise NoSuchFile(file, msg) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return self.entryclass(fp, file, sec_num) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             fp.close() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def show(self, file, edit=1): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.open(file).show(edit=edit) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |     def new(self, section): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if not SECTION_TITLES.has_key(section): | 
					
						
							|  |  |  |             raise NoSuchSection(section) | 
					
						
							|  |  |  |         maxnum = 0 | 
					
						
							|  |  |  |         for file in self.list(): | 
					
						
							|  |  |  |             sec, num = self.parse(file) | 
					
						
							|  |  |  |             if sec == section: | 
					
						
							|  |  |  |                 maxnum = max(maxnum, num) | 
					
						
							|  |  |  |         sec_num = (section, maxnum+1) | 
					
						
							|  |  |  |         file = NEWFILENAME % sec_num | 
					
						
							|  |  |  |         return self.entryclass(None, file, sec_num) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FaqWizard: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.ui = UserInput() | 
					
						
							|  |  |  |         self.dir = FaqDir() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def go(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         print 'Content-type: text/html' | 
					
						
							|  |  |  |         req = self.ui.req or 'home' | 
					
						
							|  |  |  |         mname = 'do_%s' % req | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             meth = getattr(self, mname) | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |             self.error("Bad request type %r." % (req,)) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 meth() | 
					
						
							|  |  |  |             except InvalidFile, exc: | 
					
						
							|  |  |  |                 self.error("Invalid entry file name %s" % exc.file) | 
					
						
							|  |  |  |             except NoSuchFile, exc: | 
					
						
							|  |  |  |                 self.error("No entry with file name %s" % exc.file) | 
					
						
							|  |  |  |             except NoSuchSection, exc: | 
					
						
							|  |  |  |                 self.error("No section number %s" % exc.section) | 
					
						
							|  |  |  |         self.epilogue() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def error(self, message, **kw): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_ERROR) | 
					
						
							|  |  |  |         emit(message, kw) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def prologue(self, title, entry=None, **kw): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         emit(PROLOGUE, entry, kwdict=kw, title=escape(title)) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def epilogue(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         emit(EPILOGUE) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_home(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_HOME) | 
					
						
							|  |  |  |         emit(HOME) | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_debug(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue("FAQ Wizard Debugging") | 
					
						
							|  |  |  |         form = cgi.FieldStorage() | 
					
						
							|  |  |  |         cgi.print_form(form) | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  |         cgi.print_environ(os.environ) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         cgi.print_directory() | 
					
						
							|  |  |  |         cgi.print_arguments() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_search(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         query = self.ui.query | 
					
						
							|  |  |  |         if not query: | 
					
						
							|  |  |  |             self.error("Empty query string!") | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if self.ui.querytype == 'simple': | 
					
						
							|  |  |  |             query = re.escape(query) | 
					
						
							|  |  |  |             queries = [query] | 
					
						
							|  |  |  |         elif self.ui.querytype in ('anykeywords', 'allkeywords'): | 
					
						
							|  |  |  |             words = filter(None, re.split('\W+', query)) | 
					
						
							|  |  |  |             if not words: | 
					
						
							|  |  |  |                 self.error("No keywords specified!") | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             words = map(lambda w: r'\b%s\b' % w, words) | 
					
						
							|  |  |  |             if self.ui.querytype[:3] == 'any': | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |                 queries = ['|'.join(words)] | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 # Each of the individual queries must match | 
					
						
							|  |  |  |                 queries = words | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # Default to regular expression | 
					
						
							|  |  |  |             queries = [query] | 
					
						
							|  |  |  |         self.prologue(T_SEARCH) | 
					
						
							|  |  |  |         progs = [] | 
					
						
							|  |  |  |         for query in queries: | 
					
						
							|  |  |  |             if self.ui.casefold == 'no': | 
					
						
							|  |  |  |                 p = re.compile(query) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 p = re.compile(query, re.IGNORECASE) | 
					
						
							|  |  |  |             progs.append(p) | 
					
						
							|  |  |  |         hits = [] | 
					
						
							|  |  |  |         for file in self.dir.list(): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 entry = self.dir.open(file) | 
					
						
							|  |  |  |             except FileError: | 
					
						
							|  |  |  |                 constants | 
					
						
							|  |  |  |             for p in progs: | 
					
						
							|  |  |  |                 if not p.search(entry.title) and not p.search(entry.body): | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 hits.append(file) | 
					
						
							|  |  |  |         if not hits: | 
					
						
							|  |  |  |             emit(NO_HITS, self.ui, count=0) | 
					
						
							|  |  |  |         elif len(hits) <= MAXHITS: | 
					
						
							|  |  |  |             if len(hits) == 1: | 
					
						
							|  |  |  |                 emit(ONE_HIT, count=1) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 emit(FEW_HITS, count=len(hits)) | 
					
						
							|  |  |  |             self.format_all(hits, headers=0) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             emit(MANY_HITS, count=len(hits)) | 
					
						
							|  |  |  |             self.format_index(hits) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_all(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_ALL) | 
					
						
							|  |  |  |         files = self.dir.list() | 
					
						
							|  |  |  |         self.last_changed(files) | 
					
						
							|  |  |  |         self.format_index(files, localrefs=1) | 
					
						
							|  |  |  |         self.format_all(files) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_compat(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         files = self.dir.list() | 
					
						
							|  |  |  |         emit(COMPAT) | 
					
						
							|  |  |  |         self.last_changed(files) | 
					
						
							|  |  |  |         self.format_index(files, localrefs=1) | 
					
						
							|  |  |  |         self.format_all(files, edit=0) | 
					
						
							|  |  |  |         sys.exit(0)                     # XXX Hack to suppress epilogue | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def last_changed(self, files): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         latest = 0 | 
					
						
							|  |  |  |         for file in files: | 
					
						
							|  |  |  |             entry = self.dir.open(file) | 
					
						
							|  |  |  |             if entry: | 
					
						
							|  |  |  |                 mtime = mtime = entry.getmtime() | 
					
						
							|  |  |  |                 if mtime > latest: | 
					
						
							|  |  |  |                     latest = mtime | 
					
						
							|  |  |  |         print time.strftime(LAST_CHANGED, time.localtime(latest)) | 
					
						
							|  |  |  |         emit(EXPLAIN_MARKS) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 06:28:40 +00:00
										 |  |  |     def format_all(self, files, edit=1, headers=1): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         sec = 0 | 
					
						
							|  |  |  |         for file in files: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 entry = self.dir.open(file) | 
					
						
							|  |  |  |             except NoSuchFile: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if headers and entry.sec != sec: | 
					
						
							|  |  |  |                 sec = entry.sec | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     title = SECTION_TITLES[sec] | 
					
						
							|  |  |  |                 except KeyError: | 
					
						
							|  |  |  |                     title = "Untitled" | 
					
						
							|  |  |  |                 emit("\n<HR>\n<H1>%(sec)s. %(title)s</H1>\n", | 
					
						
							|  |  |  |                      sec=sec, title=title) | 
					
						
							|  |  |  |             entry.show(edit=edit) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_index(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_INDEX) | 
					
						
							|  |  |  |         files = self.dir.list() | 
					
						
							|  |  |  |         self.last_changed(files) | 
					
						
							|  |  |  |         self.format_index(files, add=1) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 19:10:37 +00:00
										 |  |  |     def format_index(self, files, add=0, localrefs=0): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         sec = 0 | 
					
						
							|  |  |  |         for file in files: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 entry = self.dir.open(file) | 
					
						
							|  |  |  |             except NoSuchFile: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if entry.sec != sec: | 
					
						
							|  |  |  |                 if sec: | 
					
						
							|  |  |  |                     if add: | 
					
						
							|  |  |  |                         emit(INDEX_ADDSECTION, sec=sec) | 
					
						
							|  |  |  |                     emit(INDEX_ENDSECTION, sec=sec) | 
					
						
							|  |  |  |                 sec = entry.sec | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     title = SECTION_TITLES[sec] | 
					
						
							|  |  |  |                 except KeyError: | 
					
						
							|  |  |  |                     title = "Untitled" | 
					
						
							|  |  |  |                 emit(INDEX_SECTION, sec=sec, title=title) | 
					
						
							|  |  |  |             if localrefs: | 
					
						
							|  |  |  |                 emit(LOCAL_ENTRY, entry) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 emit(INDEX_ENTRY, entry) | 
					
						
							|  |  |  |             entry.emit_marks() | 
					
						
							|  |  |  |         if sec: | 
					
						
							|  |  |  |             if add: | 
					
						
							|  |  |  |                 emit(INDEX_ADDSECTION, sec=sec) | 
					
						
							|  |  |  |             emit(INDEX_ENDSECTION, sec=sec) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_recent(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if not self.ui.days: | 
					
						
							|  |  |  |             days = 1 | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |             days = float(self.ui.days) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             cutoff = now - days * 24 * 3600 | 
					
						
							|  |  |  |         except OverflowError: | 
					
						
							|  |  |  |             cutoff = 0 | 
					
						
							|  |  |  |         list = [] | 
					
						
							|  |  |  |         for file in self.dir.list(): | 
					
						
							|  |  |  |             entry = self.dir.open(file) | 
					
						
							|  |  |  |             if not entry: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             mtime = entry.getmtime() | 
					
						
							|  |  |  |             if mtime >= cutoff: | 
					
						
							|  |  |  |                 list.append((mtime, file)) | 
					
						
							|  |  |  |         list.sort() | 
					
						
							|  |  |  |         list.reverse() | 
					
						
							|  |  |  |         self.prologue(T_RECENT) | 
					
						
							|  |  |  |         if days <= 1: | 
					
						
							|  |  |  |             period = "%.2g hours" % (days*24) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             period = "%.6g days" % days | 
					
						
							|  |  |  |         if not list: | 
					
						
							|  |  |  |             emit(NO_RECENT, period=period) | 
					
						
							|  |  |  |         elif len(list) == 1: | 
					
						
							|  |  |  |             emit(ONE_RECENT, period=period) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             emit(SOME_RECENT, period=period, count=len(list)) | 
					
						
							|  |  |  |         self.format_all(map(lambda (mtime, file): file, list), headers=0) | 
					
						
							|  |  |  |         emit(TAIL_RECENT) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_roulette(self): | 
					
						
							| 
									
										
										
										
											1998-05-20 17:13:01 +00:00
										 |  |  |         import random | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         files = self.dir.list() | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |         if not files: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             self.error("No entries.") | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											1998-05-20 17:13:01 +00:00
										 |  |  |         file = random.choice(files) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_ROULETTE) | 
					
						
							|  |  |  |         emit(ROULETTE) | 
					
						
							|  |  |  |         self.dir.show(file) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_help(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_HELP) | 
					
						
							|  |  |  |         emit(HELP) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_show(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         entry = self.dir.open(self.ui.file) | 
					
						
							|  |  |  |         self.prologue(T_SHOW) | 
					
						
							|  |  |  |         entry.show() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_add(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_ADD) | 
					
						
							|  |  |  |         emit(ADD_HEAD) | 
					
						
							|  |  |  |         sections = SECTION_TITLES.items() | 
					
						
							|  |  |  |         sections.sort() | 
					
						
							|  |  |  |         for section, title in sections: | 
					
						
							|  |  |  |             emit(ADD_SECTION, section=section, title=title) | 
					
						
							|  |  |  |         emit(ADD_TAIL) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_delete(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_DELETE) | 
					
						
							|  |  |  |         emit(DELETE) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_log(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         entry = self.dir.open(self.ui.file) | 
					
						
							|  |  |  |         self.prologue(T_LOG, entry) | 
					
						
							|  |  |  |         emit(LOG, entry) | 
					
						
							|  |  |  |         self.rlog(interpolate(SH_RLOG, entry), entry) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def rlog(self, command, entry=None): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         output = os.popen(command).read() | 
					
						
							|  |  |  |         sys.stdout.write('<PRE>') | 
					
						
							|  |  |  |         athead = 0 | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         lines = output.split('\n') | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         while lines and not lines[-1]: | 
					
						
							|  |  |  |             del lines[-1] | 
					
						
							|  |  |  |         if lines: | 
					
						
							|  |  |  |             line = lines[-1] | 
					
						
							|  |  |  |             if line[:1] == '=' and len(line) >= 40 and \ | 
					
						
							|  |  |  |                line == line[0]*len(line): | 
					
						
							|  |  |  |                 del lines[-1] | 
					
						
							|  |  |  |         headrev = None | 
					
						
							|  |  |  |         for line in lines: | 
					
						
							|  |  |  |             if entry and athead and line[:9] == 'revision ': | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |                 rev = line[9:].split() | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |                 mami = revparse(rev) | 
					
						
							|  |  |  |                 if not mami: | 
					
						
							|  |  |  |                     print line | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     emit(REVISIONLINK, entry, rev=rev, line=line) | 
					
						
							|  |  |  |                     if mami[1] > 1: | 
					
						
							|  |  |  |                         prev = "%d.%d" % (mami[0], mami[1]-1) | 
					
						
							|  |  |  |                         emit(DIFFLINK, entry, prev=prev, rev=rev) | 
					
						
							|  |  |  |                     if headrev: | 
					
						
							|  |  |  |                         emit(DIFFLINK, entry, prev=rev, rev=headrev) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         headrev = rev | 
					
						
							|  |  |  |                     print | 
					
						
							|  |  |  |                 athead = 0 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 athead = 0 | 
					
						
							|  |  |  |                 if line[:1] == '-' and len(line) >= 20 and \ | 
					
						
							|  |  |  |                    line == len(line) * line[0]: | 
					
						
							|  |  |  |                     athead = 1 | 
					
						
							|  |  |  |                     sys.stdout.write('<HR>') | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     print line | 
					
						
							|  |  |  |         print '</PRE>' | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 19:10:37 +00:00
										 |  |  |     def do_revision(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         entry = self.dir.open(self.ui.file) | 
					
						
							|  |  |  |         rev = self.ui.rev | 
					
						
							|  |  |  |         mami = revparse(rev) | 
					
						
							|  |  |  |         if not mami: | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |             self.error("Invalid revision number: %r." % (rev,)) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_REVISION, entry) | 
					
						
							|  |  |  |         self.shell(interpolate(SH_REVISION, entry, rev=rev)) | 
					
						
							| 
									
										
										
										
											1997-05-26 19:10:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  |     def do_diff(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         entry = self.dir.open(self.ui.file) | 
					
						
							|  |  |  |         prev = self.ui.prev | 
					
						
							|  |  |  |         rev = self.ui.rev | 
					
						
							|  |  |  |         mami = revparse(rev) | 
					
						
							|  |  |  |         if not mami: | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |             self.error("Invalid revision number: %r." % (rev,)) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if prev: | 
					
						
							|  |  |  |             if not revparse(prev): | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |                 self.error("Invalid previous revision number: %r." % (prev,)) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             prev = '%d.%d' % (mami[0], mami[1]) | 
					
						
							|  |  |  |         self.prologue(T_DIFF, entry) | 
					
						
							|  |  |  |         self.shell(interpolate(SH_RDIFF, entry, rev=rev, prev=prev)) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def shell(self, command): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         output = os.popen(command).read() | 
					
						
							|  |  |  |         sys.stdout.write('<PRE>') | 
					
						
							|  |  |  |         print escape(output) | 
					
						
							|  |  |  |         print '</PRE>' | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_new(self): | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         entry = self.dir.new(section=int(self.ui.section)) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         entry.version = '*new*' | 
					
						
							|  |  |  |         self.prologue(T_EDIT) | 
					
						
							|  |  |  |         emit(EDITHEAD) | 
					
						
							|  |  |  |         emit(EDITFORM1, entry, editversion=entry.version) | 
					
						
							|  |  |  |         emit(EDITFORM2, entry, load_my_cookie()) | 
					
						
							|  |  |  |         emit(EDITFORM3) | 
					
						
							|  |  |  |         entry.show(edit=0) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_edit(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         entry = self.dir.open(self.ui.file) | 
					
						
							|  |  |  |         entry.load_version() | 
					
						
							|  |  |  |         self.prologue(T_EDIT) | 
					
						
							|  |  |  |         emit(EDITHEAD) | 
					
						
							|  |  |  |         emit(EDITFORM1, entry, editversion=entry.version) | 
					
						
							|  |  |  |         emit(EDITFORM2, entry, load_my_cookie()) | 
					
						
							|  |  |  |         emit(EDITFORM3) | 
					
						
							|  |  |  |         entry.show(edit=0) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def do_review(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         send_my_cookie(self.ui) | 
					
						
							|  |  |  |         if self.ui.editversion == '*new*': | 
					
						
							|  |  |  |             sec, num = self.dir.parse(self.ui.file) | 
					
						
							|  |  |  |             entry = self.dir.new(section=sec) | 
					
						
							|  |  |  |             entry.version = "*new*" | 
					
						
							|  |  |  |             if entry.file != self.ui.file: | 
					
						
							|  |  |  |                 self.error("Commit version conflict!") | 
					
						
							|  |  |  |                 emit(NEWCONFLICT, self.ui, sec=sec, num=num) | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             entry = self.dir.open(self.ui.file) | 
					
						
							|  |  |  |             entry.load_version() | 
					
						
							|  |  |  |         # Check that the FAQ entry number didn't change | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         if self.ui.title.split()[:1] != entry.title.split()[:1]: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             self.error("Don't change the entry number please!") | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         # Check that the edited version is the current version | 
					
						
							|  |  |  |         if entry.version != self.ui.editversion: | 
					
						
							|  |  |  |             self.error("Commit version conflict!") | 
					
						
							|  |  |  |             emit(VERSIONCONFLICT, entry, self.ui) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         commit_ok = ((not PASSWORD | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |                       or self.ui.password == PASSWORD) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |                      and self.ui.author | 
					
						
							|  |  |  |                      and '@' in self.ui.email | 
					
						
							|  |  |  |                      and self.ui.log) | 
					
						
							|  |  |  |         if self.ui.commit: | 
					
						
							|  |  |  |             if not commit_ok: | 
					
						
							|  |  |  |                 self.cantcommit() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.commit(entry) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.prologue(T_REVIEW) | 
					
						
							|  |  |  |         emit(REVIEWHEAD) | 
					
						
							|  |  |  |         entry.body = self.ui.body | 
					
						
							|  |  |  |         entry.title = self.ui.title | 
					
						
							|  |  |  |         entry.show(edit=0) | 
					
						
							|  |  |  |         emit(EDITFORM1, self.ui, entry) | 
					
						
							|  |  |  |         if commit_ok: | 
					
						
							|  |  |  |             emit(COMMIT) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											1998-12-23 21:33:09 +00:00
										 |  |  |             emit(NOCOMMIT_HEAD) | 
					
						
							|  |  |  |             self.errordetail() | 
					
						
							|  |  |  |             emit(NOCOMMIT_TAIL) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         emit(EDITFORM2, self.ui, entry, load_my_cookie()) | 
					
						
							|  |  |  |         emit(EDITFORM3) | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def cantcommit(self): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         self.prologue(T_CANTCOMMIT) | 
					
						
							|  |  |  |         print CANTCOMMIT_HEAD | 
					
						
							| 
									
										
										
										
											1998-12-23 21:33:09 +00:00
										 |  |  |         self.errordetail() | 
					
						
							|  |  |  |         print CANTCOMMIT_TAIL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def errordetail(self): | 
					
						
							|  |  |  |         if PASSWORD and self.ui.password != PASSWORD: | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |             emit(NEED_PASSWD) | 
					
						
							|  |  |  |         if not self.ui.log: | 
					
						
							|  |  |  |             emit(NEED_LOG) | 
					
						
							|  |  |  |         if not self.ui.author: | 
					
						
							|  |  |  |             emit(NEED_AUTHOR) | 
					
						
							|  |  |  |         if not self.ui.email: | 
					
						
							|  |  |  |             emit(NEED_EMAIL) | 
					
						
							| 
									
										
										
										
											1997-05-26 05:43:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def commit(self, entry): | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         file = entry.file | 
					
						
							|  |  |  |         # Normalize line endings in body | 
					
						
							|  |  |  |         if '\r' in self.ui.body: | 
					
						
							|  |  |  |             self.ui.body = re.sub('\r\n?', '\n', self.ui.body) | 
					
						
							|  |  |  |         # Normalize whitespace in title | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  |         self.ui.title = ' '.join(self.ui.title.split()) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         # Check that there were any changes | 
					
						
							|  |  |  |         if self.ui.body == entry.body and self.ui.title == entry.title: | 
					
						
							|  |  |  |             self.error("You didn't make any changes!") | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2000-03-31 00:58:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # need to lock here because otherwise the file exists and is not writable (on NT) | 
					
						
							|  |  |  |         command = interpolate(SH_LOCK, file=file) | 
					
						
							|  |  |  |         p = os.popen(command) | 
					
						
							|  |  |  |         output = p.read() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             os.unlink(file) | 
					
						
							|  |  |  |         except os.error: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             f = open(file, 'w') | 
					
						
							|  |  |  |         except IOError, why: | 
					
						
							|  |  |  |             self.error(CANTWRITE, file=file, why=why) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         date = time.ctime(now) | 
					
						
							|  |  |  |         emit(FILEHEADER, self.ui, os.environ, date=date, _file=f, _quote=0) | 
					
						
							|  |  |  |         f.write('\n') | 
					
						
							|  |  |  |         f.write(self.ui.body) | 
					
						
							|  |  |  |         f.write('\n') | 
					
						
							|  |  |  |         f.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         import tempfile | 
					
						
							| 
									
										
										
										
											2002-08-09 16:38:32 +00:00
										 |  |  |         tf = tempfile.NamedTemporaryFile() | 
					
						
							| 
									
										
										
										
											2004-08-07 21:13:46 +00:00
										 |  |  |         emit(LOGHEADER, self.ui, os.environ, date=date, _file=tf) | 
					
						
							| 
									
										
										
										
											2002-08-09 16:38:32 +00:00
										 |  |  |         tf.flush() | 
					
						
							|  |  |  |         tf.seek(0) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-08-09 16:38:32 +00:00
										 |  |  |         command = interpolate(SH_CHECKIN, file=file, tfn=tf.name) | 
					
						
							| 
									
										
										
										
											2000-03-31 00:58:00 +00:00
										 |  |  |         log("\n\n" + command) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         p = os.popen(command) | 
					
						
							|  |  |  |         output = p.read() | 
					
						
							|  |  |  |         sts = p.close() | 
					
						
							| 
									
										
										
										
											2000-03-31 00:58:00 +00:00
										 |  |  |         log("output: " + output) | 
					
						
							|  |  |  |         log("done: " + str(sts)) | 
					
						
							| 
									
										
										
										
											2002-08-09 16:38:32 +00:00
										 |  |  |         log("TempFile:\n" + tf.read() + "end") | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         if not sts: | 
					
						
							|  |  |  |             self.prologue(T_COMMITTED) | 
					
						
							|  |  |  |             emit(COMMITTED) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.error(T_COMMITFAILED) | 
					
						
							|  |  |  |             emit(COMMITFAILED, sts=sts) | 
					
						
							|  |  |  |         print '<PRE>%s</PRE>' % escape(output) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2004-08-07 21:13:46 +00:00
										 |  |  |             os.unlink(tf.name) | 
					
						
							| 
									
										
										
										
											1998-04-06 14:24:36 +00:00
										 |  |  |         except os.error: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         entry = self.dir.open(file) | 
					
						
							|  |  |  |         entry.show() | 
					
						
							| 
									
										
										
										
											1997-05-26 00:07:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | wiz = FaqWizard() | 
					
						
							|  |  |  | wiz.go() |